diff --git a/.changeset/silly-phones-watch.md b/.changeset/silly-phones-watch.md new file mode 100644 index 000000000..c045c915e --- /dev/null +++ b/.changeset/silly-phones-watch.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/telemetry': patch +--- + +Add basic error reporting to astro telemetry diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index a04b15247..3a22bc3f3 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -1,13 +1,11 @@ /* eslint-disable no-console */ import { LogOptions } from '../core/logger/core.js'; - -import { AstroTelemetry } from '@astrojs/telemetry'; import * as colors from 'kleur/colors'; import yargs from 'yargs-parser'; import { z } from 'zod'; +import { telemetry } from '../events/index.js'; import * as event from '../events/index.js'; - import add from '../core/add/index.js'; import build from '../core/build/index.js'; import { openConfig } from '../core/config.js'; @@ -15,10 +13,12 @@ import devServer from '../core/dev/index.js'; import { enableVerboseLogging, nodeLogDestination } from '../core/logger/node.js'; import { formatConfigErrorMessage, formatErrorMessage, printHelp } from '../core/messages.js'; import preview from '../core/preview/index.js'; -import { createSafeError } from '../core/util.js'; +import { createSafeError, ASTRO_VERSION } from '../core/util.js'; import { check } from './check.js'; import { openInBrowser } from './open.js'; import * as telemetryHandler from './telemetry.js'; +import { collectErrorMetadata } from '../core/errors.js'; +import { eventError, eventConfigError } from '../events/index.js'; type Arguments = yargs.Arguments; type CLICommand = @@ -61,9 +61,6 @@ function printAstroHelp() { }); } -// PACKAGE_VERSION is injected when we build and publish the astro package. -const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development'; - /** Display --version flag */ async function printVersion() { console.log(); @@ -111,7 +108,6 @@ export async function cli(args: string[]) { } else if (flags.silent) { logging.level = 'silent'; } - const telemetry = new AstroTelemetry({ version: ASTRO_VERSION }); // Special CLI Commands: "add", "docs", "telemetry" // These commands run before the user's config is parsed, and may have other special @@ -120,19 +116,19 @@ export async function cli(args: string[]) { switch (cmd) { case 'add': { try { - telemetry.record(event.eventCliSession({ cliCommand: cmd })); + telemetry.record(event.eventCliSession(cmd)); const packages = flags._.slice(3) as string[]; return await add(packages, { cwd: root, flags, logging, telemetry }); } catch (err) { - return throwAndExit(err); + return throwAndExit(cmd, err); } } case 'docs': { try { - telemetry.record(event.eventCliSession({ cliCommand: cmd })); + telemetry.record(event.eventCliSession(cmd)); return await openInBrowser('https://docs.astro.build/'); } catch (err) { - return throwAndExit(err); + return throwAndExit(cmd, err); } } case 'telemetry': { @@ -142,13 +138,13 @@ export async function cli(args: string[]) { const subcommand = flags._[3]?.toString(); return await telemetryHandler.update(subcommand, { flags, telemetry }); } catch (err) { - return throwAndExit(err); + return throwAndExit(cmd, err); } } } const { astroConfig, userConfig } = await openConfig({ cwd: root, flags, cmd }); - telemetry.record(event.eventCliSession({ cliCommand: cmd }, userConfig, flags)); + telemetry.record(event.eventCliSession(cmd, userConfig, flags)); // Common CLI Commands: // These commands run normally. All commands are assumed to have been handled @@ -159,7 +155,7 @@ export async function cli(args: string[]) { await devServer(astroConfig, { logging, telemetry }); return await new Promise(() => {}); // lives forever } catch (err) { - return throwAndExit(err); + return throwAndExit(cmd, err); } } @@ -167,7 +163,7 @@ export async function cli(args: string[]) { try { return await build(astroConfig, { logging, telemetry }); } catch (err) { - return throwAndExit(err); + return throwAndExit(cmd, err); } } @@ -181,21 +177,29 @@ export async function cli(args: string[]) { const server = await preview(astroConfig, { logging, telemetry }); return await server.closed(); // keep alive until the server is closed } catch (err) { - return throwAndExit(err); + return throwAndExit(cmd, err); } } } // No command handler matched! This is unexpected. - throwAndExit(new Error(`Error running ${cmd} -- no command found.`)); + throwAndExit(cmd, new Error(`Error running ${cmd} -- no command found.`)); } /** Display error and exit */ -function throwAndExit(err: unknown) { +function throwAndExit(cmd: string, err: unknown) { + let telemetryPromise: Promise; if (err instanceof z.ZodError) { console.error(formatConfigErrorMessage(err)); + telemetryPromise = telemetry.record(eventConfigError({ cmd, err, isFatal: true })); } else { - console.error(formatErrorMessage(createSafeError(err))); + const errorWithMetadata = collectErrorMetadata(createSafeError(err)); + console.error(formatErrorMessage(errorWithMetadata)); + telemetryPromise = telemetry.record(eventError({ cmd, err: errorWithMetadata, isFatal: true })); } - process.exit(1); + // Wait for the telemetry event to send, then exit. Ignore an error. + telemetryPromise.catch(() => undefined).then(() => process.exit(1)); + // Don't wait too long. Timeout the request faster than usual because the user is waiting. + // TODO: Investigate using an AbortController once we drop Node v14 support. + setTimeout(() => process.exit(1), 300); } diff --git a/packages/astro/src/core/errors.ts b/packages/astro/src/core/errors.ts index 8393f0d83..793cde1d1 100644 --- a/packages/astro/src/core/errors.ts +++ b/packages/astro/src/core/errors.ts @@ -5,10 +5,19 @@ import type { ViteDevServer } from 'vite'; import type { SSRError } from '../@types/astro'; import { codeFrame, createSafeError } from './util.js'; +export enum AstroErrorCodes { + // 1xxx: Astro Runtime Errors + UnknownError = 1000, + ConfigError = 1001, + // 2xxx: Astro Compiler Errors + UnknownCompilerError = 2000, + UnknownCompilerCSSError = 2001, +} export interface ErrorWithMetadata { [name: string]: any; message: string; stack: string; + code?: number; hint?: string; id?: string; frame?: string; diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index 7f592c46b..1283708b2 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -18,7 +18,7 @@ import type { AddressInfo } from 'net'; import os from 'os'; import { ZodError } from 'zod'; import type { AstroConfig } from '../@types/astro'; -import { cleanErrorStack, collectErrorMetadata } from './errors.js'; +import { cleanErrorStack, collectErrorMetadata, ErrorWithMetadata } from './errors.js'; import { emoji, getLocalAddress, padMultilineString } from './util.js'; const PREFIX_PADDING = 6; @@ -219,8 +219,7 @@ export function formatConfigErrorMessage(err: ZodError) { )}`; } -export function formatErrorMessage(_err: Error, args: string[] = []): string { - const err = collectErrorMetadata(_err); +export function formatErrorMessage(err: ErrorWithMetadata, args: string[] = []): string { args.push(`${bgRed(black(` error `))}${red(bold(padMultilineString(err.message)))}`); if (err.hint) { args.push(` ${bold('Hint:')}`); diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 8def24771..8759a2fc8 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -8,6 +8,9 @@ import type { ErrorPayload } from 'vite'; import type { AstroConfig } from '../@types/astro'; import { removeTrailingForwardSlash } from './path.js'; +// process.env.PACKAGE_VERSION is injected when we build and publish the astro package. +export const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development'; + /** Returns true if argument is an object of any prototype/class (but not null). */ export function isObject(value: unknown): value is Record { return typeof value === 'object' && value != null; diff --git a/packages/astro/src/events/error.ts b/packages/astro/src/events/error.ts new file mode 100644 index 000000000..fa9778b44 --- /dev/null +++ b/packages/astro/src/events/error.ts @@ -0,0 +1,75 @@ +import { ZodError } from 'zod'; +import { AstroErrorCodes, ErrorWithMetadata } from '../core/errors.js'; + +const EVENT_ERROR = 'ASTRO_CLI_ERROR'; + +interface ErrorEventPayload { + code: number | undefined; + isFatal: boolean; + plugin?: string | undefined; + cliCommand: string; + anonymousMessageHint?: string | undefined; +} + +interface ConfigErrorEventPayload extends ErrorEventPayload { + isConfig: true; + configErrorPaths: string[]; +} + +/** + * This regex will grab a small snippet at the start of an error message. + * This was designed to stop capturing at the first sign of some non-message + * content like a filename, filepath, or any other code-specific value. + * We also trim this value even further to just a few words. + * + * Our goal is to remove this entirely before v1.0.0 is released, as we work + * to add a proper error code system (see AstroErrorCodes for examples). + * + * TODO(fks): Remove around v1.0.0 release. + */ +const ANONYMIZE_MESSAGE_REGEX = /^(\w| )+/; +function anonymizeErrorMessage(msg: string): string | undefined { + const matchedMessage = msg.match(ANONYMIZE_MESSAGE_REGEX); + if (!matchedMessage || !matchedMessage[0]) { + return undefined; + } + return matchedMessage[0].trim().substring(0, 20); +} + +export function eventConfigError({ + err, + cmd, + isFatal, +}: { + err: ZodError; + cmd: string; + isFatal: boolean; +}): { eventName: string; payload: ConfigErrorEventPayload }[] { + const payload: ConfigErrorEventPayload = { + code: AstroErrorCodes.ConfigError, + isFatal, + isConfig: true, + cliCommand: cmd, + configErrorPaths: err.issues.map((issue) => issue.path.join('.')), + }; + return [{ eventName: EVENT_ERROR, payload }]; +} + +export function eventError({ + cmd, + err, + isFatal, +}: { + err: ErrorWithMetadata; + cmd: string; + isFatal: boolean; +}): { eventName: string; payload: ErrorEventPayload }[] { + const payload: ErrorEventPayload = { + code: err.code || AstroErrorCodes.UnknownError, + plugin: err.plugin, + cliCommand: cmd, + isFatal: isFatal, + anonymousMessageHint: anonymizeErrorMessage(err.message), + }; + return [{ eventName: EVENT_ERROR, payload }]; +} diff --git a/packages/astro/src/events/index.ts b/packages/astro/src/events/index.ts index dc768aa2d..fa17490c3 100644 --- a/packages/astro/src/events/index.ts +++ b/packages/astro/src/events/index.ts @@ -1 +1,18 @@ +import { AstroTelemetry } from '@astrojs/telemetry'; +import { ASTRO_VERSION } from '../core/util.js'; +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); + +function getViteVersion() { + try { + const { version } = require('vite/package.json'); + return version; + } catch (e) {} + return undefined; +} + +export const telemetry = new AstroTelemetry({ astroVersion: ASTRO_VERSION, viteVersion: getViteVersion() }); + +export * from './error.js'; export * from './session.js'; + diff --git a/packages/astro/src/events/session.ts b/packages/astro/src/events/session.ts index 6a246f581..3fc3be723 100644 --- a/packages/astro/src/events/session.ts +++ b/packages/astro/src/events/session.ts @@ -4,10 +4,6 @@ const require = createRequire(import.meta.url); const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED'; -interface EventCliSession { - cliCommand: string; -} - interface ConfigInfo { markdownPlugins: string[]; adapter: string | null; @@ -26,23 +22,14 @@ interface ConfigInfo { }; } -interface EventCliSessionInternal extends EventCliSession { - nodeVersion: string; - viteVersion: string; +interface EventPayload { + cliCommand: string; config?: ConfigInfo; configKeys?: string[]; flags?: string[]; optionalIntegrations?: number; } -function getViteVersion() { - try { - const { version } = require('vite/package.json'); - return version; - } catch (e) {} - return undefined; -} - const multiLevelKeys = new Set([ 'build', 'markdown', @@ -82,10 +69,10 @@ function configKeys(obj: Record | undefined, parentKey: string): st } export function eventCliSession( - event: EventCliSession, + cliCommand: string, userConfig?: AstroUserConfig, flags?: Record -): { eventName: string; payload: EventCliSessionInternal }[] { +): { eventName: string; payload: EventPayload }[] { // Filter out falsy integrations const configValues = userConfig ? { @@ -117,13 +104,9 @@ export function eventCliSession( // Filter out yargs default `_` flag which is the cli command const cliFlags = flags ? Object.keys(flags).filter((name) => name != '_') : undefined; - const payload: EventCliSessionInternal = { - cliCommand: event.cliCommand, - // Versions - viteVersion: getViteVersion(), - nodeVersion: process.version.replace(/^v?/, ''), + const payload: EventPayload = { + cliCommand, configKeys: userConfig ? configKeys(userConfig, '') : undefined, - // Config Values config: configValues, flags: cliFlags, }; diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index bf1a57a51..a57e2bba0 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -6,7 +6,7 @@ import type { SSROptions } from '../core/render/dev/index'; import { Readable } from 'stream'; import stripAnsi from 'strip-ansi'; import { call as callEndpoint } from '../core/endpoint/dev/index.js'; -import { fixViteErrorMessage } from '../core/errors.js'; +import { collectErrorMetadata, fixViteErrorMessage } from '../core/errors.js'; import { error, info, LogOptions, warn } from '../core/logger/core.js'; import * as msg from '../core/messages.js'; import { appendForwardSlash } from '../core/path.js'; @@ -320,7 +320,8 @@ async function handleRequest( } } catch (_err) { const err = fixViteErrorMessage(createSafeError(_err), viteServer); - error(logging, null, msg.formatErrorMessage(err)); + const errorWithMetadata = collectErrorMetadata(_err); + error(logging, null, msg.formatErrorMessage(errorWithMetadata)); handle500Response(viteServer, origin, req, res, err); } } diff --git a/packages/astro/src/vite-plugin-astro/compile.ts b/packages/astro/src/vite-plugin-astro/compile.ts index 8c4590967..2322d1627 100644 --- a/packages/astro/src/vite-plugin-astro/compile.ts +++ b/packages/astro/src/vite-plugin-astro/compile.ts @@ -8,6 +8,7 @@ import { fileURLToPath } from 'url'; import { prependForwardSlash } from '../core/path.js'; import { viteID } from '../core/util.js'; import { transformWithVite } from './styles.js'; +import { AstroErrorCodes } from '../core/errors.js'; type CompilationCache = Map; type CompileResult = TransformResult & { rawCSSDeps: Set }; @@ -120,11 +121,19 @@ async function compile({ return null; } }, + }).catch((err) => { + // throw compiler errors here if encountered + err.code = err.code || AstroErrorCodes.UnknownCompilerError; + throw err; + }).then((result) => { + // throw CSS transform errors here if encountered + if (cssTransformError) { + (cssTransformError as any).code = (cssTransformError as any).code || AstroErrorCodes.UnknownCompilerCSSError; + throw cssTransformError; + } + return result; }); - // throw CSS transform errors here if encountered - if (cssTransformError) throw cssTransformError; - const compileResult: CompileResult = Object.create(transformResult, { rawCSSDeps: { value: rawCSSDeps, diff --git a/packages/astro/test/errors.test.js b/packages/astro/test/errors.test.js index 01fe61b9a..fdf89a021 100644 --- a/packages/astro/test/errors.test.js +++ b/packages/astro/test/errors.test.js @@ -97,4 +97,5 @@ describe('Error display', () => { expect($('h1').text()).to.equal('No mismatch'); }); }); + }); diff --git a/packages/astro/test/events.test.js b/packages/astro/test/events.test.js index 3eeef269c..42db3242e 100644 --- a/packages/astro/test/events.test.js +++ b/packages/astro/test/events.test.js @@ -1,8 +1,10 @@ import { expect } from 'chai'; +import { AstroErrorCodes } from '../dist/core/errors.js'; import * as events from '../dist/events/index.js'; -describe('Session event', () => { - describe('top-level', () => { +describe('Events', () => { + + describe('eventCliSession()', () => { it('All top-level keys added', () => { const config = { root: 1, @@ -23,9 +25,7 @@ describe('Session event', () => { ); expect(payload.configKeys).to.deep.equal(expected); }); - }); - describe('config.build', () => { it('configKeys includes format', () => { const config = { srcDir: 1, @@ -57,9 +57,7 @@ describe('Session event', () => { ); expect(payload.config.build.format).to.equal('file'); }); - }); - describe('config.server', () => { it('configKeys includes server props', () => { const config = { srcDir: 1, @@ -76,9 +74,7 @@ describe('Session event', () => { ); expect(payload.configKeys).to.deep.equal(['srcDir', 'server', 'server.host', 'server.port']); }); - }); - describe('config.markdown', () => { it('configKeys is deep', () => { const config = { publicDir: 1, @@ -128,10 +124,8 @@ describe('Session event', () => { ); expect(payload.config.markdown.syntaxHighlight).to.equal('shiki'); }); - }); - describe('config.vite', () => { - it('top-level keys are captured', async () => { + it('top-level vite keys are captured', async () => { const config = { root: 'some/thing', vite: { @@ -376,23 +370,21 @@ describe('Session event', () => { 'vite.worker.plugins', ]); }); - }); - it('falsy integrations', () => { - const config = { - srcDir: 1, - integrations: [null, undefined, false], - }; - const [{ payload }] = events.eventCliSession( - { - cliCommand: 'dev', - }, - config - ); - expect(payload.config.integrations.length).to.equal(0); - }); + it('falsy integrations', () => { + const config = { + srcDir: 1, + integrations: [null, undefined, false], + }; + const [{ payload }] = events.eventCliSession( + { + cliCommand: 'dev', + }, + config + ); + expect(payload.config.integrations.length).to.equal(0); + }); - describe('flags', () => { it('includes cli flags in payload', () => { const config = {}; const flags = { @@ -424,4 +416,75 @@ describe('Session event', () => { ]); }); }); + + describe('eventConfigError()', () => { + it('returns the expected event and payload', () => { + const [event] = events.eventConfigError({ + err: { issues: [{ path: ['a', 'b', 'c'] }, { path: ['d', 'e', 'f'] }] }, + cmd: 'COMMAND_NAME', + isFatal: true + }); + expect(event).to.deep.equal({ + eventName: 'ASTRO_CLI_ERROR', + payload: { + code: AstroErrorCodes.ConfigError, + isFatal: true, + isConfig: true, + cliCommand: 'COMMAND_NAME', + configErrorPaths: ['a.b.c', 'd.e.f'], + } + }); + }); + }); + + describe('eventError()', () => { + it('returns the expected event payload with a detailed error object', () => { + const errorWithFullMetadata = new Error('TEST ERROR MESSAGE'); + errorWithFullMetadata.code = 1234; + errorWithFullMetadata.plugin = 'TEST PLUGIN'; + const [event] = events.eventError({ + err: errorWithFullMetadata, + cmd: 'COMMAND_NAME', + isFatal: true + }); + expect(event).to.deep.equal({ + eventName: 'ASTRO_CLI_ERROR', + payload: { + code: 1234, + plugin: 'TEST PLUGIN', + isFatal: true, + cliCommand: 'COMMAND_NAME', + anonymousMessageHint: 'TEST ERROR MESSAGE', + } + }); + }); + + it('returns the expected event payload with a generic error', () => { + const [event] = events.eventError({ + err: new Error('TEST ERROR MESSAGE'), + cmd: 'COMMAND_NAME', + isFatal: false + }); + expect(event).to.deep.equal({ + eventName: 'ASTRO_CLI_ERROR', + payload: { + code: AstroErrorCodes.UnknownError, + plugin: undefined, + isFatal: false, + cliCommand: 'COMMAND_NAME', + anonymousMessageHint: 'TEST ERROR MESSAGE', + } + }); + }); + + it('properly creates anonymousMessageHint from a basic error message', () => { + const [event] = events.eventError({ + err: new Error('TEST ERROR MESSAGE: Sensitive data is "/Users/MYNAME/foo.astro"'), + cmd: 'COMMAND_NAME', + isFatal: true + }); + expect(event.payload.anonymousMessageHint).to.equal('TEST ERROR MESSAGE'); + }); + + }); }); diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts index dbb34740d..60562d981 100644 --- a/packages/create-astro/src/index.ts +++ b/packages/create-astro/src/index.ts @@ -14,6 +14,7 @@ import { TEMPLATES } from './templates.js'; function wait(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } + function logAndWait(message: string, ms = 100) { console.log(message); return wait(ms); diff --git a/packages/telemetry/src/index.ts b/packages/telemetry/src/index.ts index f0315e16c..0bba53e5a 100644 --- a/packages/telemetry/src/index.ts +++ b/packages/telemetry/src/index.ts @@ -7,7 +7,7 @@ import { post } from './post.js'; import { getProjectInfo, ProjectInfo } from './project-info.js'; import { getSystemInfo, SystemInfo } from './system-info.js'; -export type AstroTelemetryOptions = { version: string }; +export type AstroTelemetryOptions = { astroVersion: string; viteVersion: string }; export type TelemetryEvent = { eventName: string; payload: Record }; interface EventContext { anonymousId: string; @@ -25,7 +25,10 @@ export class AstroTelemetry { private debug = debug('astro:telemetry'); private get astroVersion() { - return this.opts.version; + return this.opts.astroVersion; + } + private get viteVersion() { + return this.opts.viteVersion; } private get ASTRO_TELEMETRY_DISABLED() { return process.env.ASTRO_TELEMETRY_DISABLED; @@ -131,7 +134,7 @@ export class AstroTelemetry { } const meta: EventMeta = { - ...getSystemInfo(this.astroVersion), + ...getSystemInfo({ astroVersion: this.astroVersion, viteVersion: this.viteVersion }), isGit: this.anonymousProjectInfo.isGit, }; @@ -141,6 +144,12 @@ export class AstroTelemetry { anonymousSessionId: this.anonymousSessionId, }; + // Every CI session also creates a new user, which blows up telemetry. + // To solve this, we track all CI runs under a single "CI" anonymousId. + if (meta.isCI) { + context.anonymousId = `CI.${meta.ciName || 'UNKNOWN'}`; + } + return post({ context, meta, diff --git a/packages/telemetry/src/system-info.ts b/packages/telemetry/src/system-info.ts index 9fe628ff0..5ff3b9559 100644 --- a/packages/telemetry/src/system-info.ts +++ b/packages/telemetry/src/system-info.ts @@ -31,6 +31,9 @@ export type SystemInfo = { systemPlatform: NodeJS.Platform; systemRelease: string; systemArchitecture: string; + astroVersion: string; + nodeVersion: string; + viteVersion: string; cpuCount: number; cpuModel: string | null; cpuSpeed: number | null; @@ -39,18 +42,21 @@ export type SystemInfo = { isWSL: boolean; isCI: boolean; ciName: string | null; - astroVersion: string; }; let meta: SystemInfo | undefined; -export function getSystemInfo(astroVersion: string): SystemInfo { +export function getSystemInfo(versions: {viteVersion: string, astroVersion: string}): SystemInfo { if (meta) { return meta; } const cpus = os.cpus() || []; meta = { + // Version information + nodeVersion: process.version.replace(/^v?/, ''), + viteVersion: versions.viteVersion, + astroVersion: versions.astroVersion, // Software information systemPlatform: os.platform(), systemRelease: os.release(), @@ -65,7 +71,6 @@ export function getSystemInfo(astroVersion: string): SystemInfo { isWSL, isCI, ciName, - astroVersion, }; return meta!; diff --git a/packages/webapi/mod.d.ts b/packages/webapi/mod.d.ts index a3c49dc5c..b385e82a5 100644 --- a/packages/webapi/mod.d.ts +++ b/packages/webapi/mod.d.ts @@ -1,5 +1,5 @@ export { pathToPosix } from './lib/utils'; -export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter } from './mod.js'; +export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, } from './mod.js'; export declare const polyfill: { (target: any, options?: PolyfillOptions): any; internals(target: any, name: string): any;