mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Even more better error messages
This commit is contained in:
parent
b72353956b
commit
e24d47b80f
@ -1,4 +1,5 @@
|
||||
import { traceSpan } from '@/utils/telemetry';
|
||||
import { StackAssertionError, captureError, errorToNiceString } from '@stackframe/stack-shared/dist/utils/errors';
|
||||
import { FreestyleSandboxes } from 'freestyle-sandboxes';
|
||||
|
||||
export class TracedFreestyleSandboxes {
|
||||
|
||||
@ -6,7 +6,7 @@ import { getEnvVariable, getNodeEnvironment } from '@stackframe/stack-shared/dis
|
||||
import { StackAssertionError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { globalVar } from "@stackframe/stack-shared/dist/utils/globals";
|
||||
import { deepPlainEquals, filterUndefined, typedFromEntries, typedKeys } from "@stackframe/stack-shared/dist/utils/objects";
|
||||
import { ignoreUnhandledRejection } from "@stackframe/stack-shared/dist/utils/promises";
|
||||
import { concatStacktracesIfRejected, ignoreUnhandledRejection } from "@stackframe/stack-shared/dist/utils/promises";
|
||||
import { Result } from "@stackframe/stack-shared/dist/utils/results";
|
||||
import { isPromise } from "util/types";
|
||||
import { runMigrationNeeded } from "./auto-migrations";
|
||||
@ -305,8 +305,10 @@ async function rawQueryArray<Q extends RawQuery<any>[]>(tx: PrismaClientTransact
|
||||
const postProcessed = combinedQuery.postProcess(rawResult as any);
|
||||
// If the postProcess is async, postProcessed is a Promise. If that Promise is rejected, it will cause an unhandled promise rejection.
|
||||
// We don't want that, because Vercel crashes on unhandled promise rejections.
|
||||
// We also want to concat the current stack trace to the error, so we can see where the rawQuery function was called
|
||||
if (isPromise(postProcessed)) {
|
||||
ignoreUnhandledRejection(postProcessed);
|
||||
concatStacktracesIfRejected(postProcessed);
|
||||
}
|
||||
|
||||
return postProcessed;
|
||||
|
||||
@ -28,6 +28,8 @@ function removeStacktraceNameLine(stack: string): string {
|
||||
/**
|
||||
* Concatenates the (original) stacktraces of the given errors onto the first.
|
||||
*
|
||||
* Note: Very often, the concatStacktracesIfRejected function in promises.tsx is an easier way to use this function.
|
||||
*
|
||||
* Useful when you invoke an async function to receive a promise without awaiting it immediately. Browsers are smart
|
||||
* enough to keep track of the call stack in async function calls when you invoke `.then` within the same async tick,
|
||||
* but if you don't, the stacktrace will be lost.
|
||||
@ -36,7 +38,7 @@ function removeStacktraceNameLine(stack: string): string {
|
||||
*
|
||||
* ```tsx
|
||||
* async function log() {
|
||||
* await wait(0); // simulate an put the task on the event loop
|
||||
* await wait(0); // put the task on the event loop
|
||||
* console.log(new Error().stack);
|
||||
* }
|
||||
*
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { KnownError } from "..";
|
||||
import { StackAssertionError, captureError, concatStacktraces } from "./errors";
|
||||
import { StackAssertionError, captureError, concatStacktraces, errorToNiceString } from "./errors";
|
||||
import { DependenciesMap } from "./maps";
|
||||
import { Result } from "./results";
|
||||
import { generateUuid } from "./uuids";
|
||||
@ -243,6 +243,20 @@ import.meta.vitest?.test("ignoreUnhandledRejection", async ({ expect }) => {
|
||||
await expect(rejectPromise).rejects.toBe(error);
|
||||
});
|
||||
|
||||
/**
|
||||
* See concatStacktraces for more information.
|
||||
*/
|
||||
export function concatStacktracesIfRejected<T>(promise: Promise<T>): void {
|
||||
const currentError = new Error();
|
||||
promise.catch(error => {
|
||||
if (error instanceof Error) {
|
||||
concatStacktraces(error, currentError);
|
||||
} else {
|
||||
// we can only concatenate errors, so we'll just ignore the non-error
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function wait(ms: number) {
|
||||
if (!Number.isFinite(ms) || ms < 0) {
|
||||
throw new StackAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);
|
||||
@ -336,18 +350,19 @@ export function runAsynchronously(
|
||||
if (typeof promiseOrFunc === "function") {
|
||||
promiseOrFunc = promiseOrFunc();
|
||||
}
|
||||
const duringError = new Error();
|
||||
promiseOrFunc?.catch(error => {
|
||||
options.onError?.(error);
|
||||
const newError = new StackAssertionError(
|
||||
"Uncaught error in asynchronous function: " + errorToNiceString(error),
|
||||
{ cause: error },
|
||||
);
|
||||
concatStacktraces(newError, duringError);
|
||||
if (!options.noErrorLogging) {
|
||||
captureError("runAsynchronously", newError);
|
||||
}
|
||||
});
|
||||
if (promiseOrFunc) {
|
||||
concatStacktracesIfRejected(promiseOrFunc);
|
||||
promiseOrFunc.catch(error => {
|
||||
options.onError?.(error);
|
||||
const newError = new StackAssertionError(
|
||||
"Uncaught error in asynchronous function: " + errorToNiceString(error),
|
||||
{ cause: error },
|
||||
);
|
||||
if (!options.noErrorLogging) {
|
||||
captureError("runAsynchronously", newError);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
import.meta.vitest?.test("runAsynchronously", ({ expect }) => {
|
||||
// Simple test to verify the function exists and can be called
|
||||
|
||||
Loading…
Reference in New Issue
Block a user