@stackframe/stack-shared 2.8.27 → 2.8.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/esm/helpers/emails.js +31 -7
- package/dist/esm/helpers/emails.js.map +1 -1
- package/dist/esm/interface/admin-interface.js +22 -9
- package/dist/esm/interface/admin-interface.js.map +1 -1
- package/dist/esm/interface/crud/config.js +40 -0
- package/dist/esm/interface/crud/config.js.map +1 -0
- package/dist/esm/interface/server-interface.js +26 -0
- package/dist/esm/interface/server-interface.js.map +1 -1
- package/dist/esm/utils/errors.js.map +1 -1
- package/dist/esm/utils/esbuild.js +15 -11
- package/dist/esm/utils/esbuild.js.map +1 -1
- package/dist/esm/utils/promises.js +24 -13
- package/dist/esm/utils/promises.js.map +1 -1
- package/dist/esm/utils/telemetry.js +39 -0
- package/dist/esm/utils/telemetry.js.map +1 -0
- package/dist/helpers/emails.d.mts +1 -1
- package/dist/helpers/emails.d.ts +1 -1
- package/dist/helpers/emails.js +31 -7
- package/dist/helpers/emails.js.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/interface/admin-interface.d.mts +5 -6
- package/dist/interface/admin-interface.d.ts +5 -6
- package/dist/interface/admin-interface.js +22 -9
- package/dist/interface/admin-interface.js.map +1 -1
- package/dist/interface/crud/config.d.mts +49 -0
- package/dist/interface/crud/config.d.ts +49 -0
- package/dist/interface/crud/config.js +79 -0
- package/dist/interface/crud/config.js.map +1 -0
- package/dist/interface/server-interface.d.mts +9 -0
- package/dist/interface/server-interface.d.ts +9 -0
- package/dist/interface/server-interface.js +26 -0
- package/dist/interface/server-interface.js.map +1 -1
- package/dist/utils/errors.d.mts +3 -1
- package/dist/utils/errors.d.ts +3 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/esbuild.js +15 -11
- package/dist/utils/esbuild.js.map +1 -1
- package/dist/utils/promises.d.mts +5 -1
- package/dist/utils/promises.d.ts +5 -1
- package/dist/utils/promises.js +24 -12
- package/dist/utils/promises.js.map +1 -1
- package/dist/utils/telemetry.d.mts +13 -0
- package/dist/utils/telemetry.d.ts +13 -0
- package/dist/utils/telemetry.js +66 -0
- package/dist/utils/telemetry.js.map +1 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/errors.tsx"],"sourcesContent":["import { globalVar } from \"./globals\";\nimport { Json } from \"./json\";\nimport { pick } from \"./objects\";\nimport { nicify } from \"./strings\";\n\n\nexport function throwErr(errorMessage: string, extraData?: any): never;\nexport function throwErr(error: Error): never;\nexport function throwErr(...args: StatusErrorConstructorParameters): never;\nexport function throwErr(...args: any[]): never {\n if (typeof args[0] === \"string\") {\n throw new StackAssertionError(args[0], args[1]);\n } else if (args[0] instanceof Error) {\n throw args[0];\n } else {\n // @ts-expect-error\n throw new StatusError(...args);\n }\n}\n\nfunction removeStacktraceNameLine(stack: string): string {\n // some browsers (eg. Chrome) prepend the stack with an extra line with the error name\n const addsNameLine = new Error().stack?.startsWith(\"Error\\n\");\n return stack.split(\"\\n\").slice(addsNameLine ? 1 : 0).join(\"\\n\");\n}\n\n\n/**\n * Concatenates the (original) stacktraces of the given errors onto the first.\n *\n * Useful when you invoke an async function to receive a promise without awaiting it immediately. Browsers are smart\n * enough to keep track of the call stack in async function calls when you invoke `.then` within the same async tick,\n * but if you don't, the stacktrace will be lost.\n *\n * Here's an example of the unwanted behavior:\n *\n * ```tsx\n * async function log() {\n * await wait(0); // simulate an put the task on the event loop\n * console.log(new Error().stack);\n * }\n *\n * async function main() {\n * await log(); // good; prints both \"log\" and \"main\" on the stacktrace\n * log(); // bad; prints only \"log\" on the stacktrace\n * }\n * ```\n */\nexport function concatStacktraces(first: Error, ...errors: Error[]): void {\n // some browsers (eg. Firefox) add an extra empty line at the end\n const addsEmptyLineAtEnd = first.stack?.endsWith(\"\\n\");\n\n\n // Add a reference to this function itself so that we know that stacktraces were concatenated\n // If you are coming here from a stacktrace, please know that the two parts before and after this line are different\n // stacktraces that were concatenated with concatStacktraces\n const separator = removeStacktraceNameLine(new Error().stack ?? \"\").split(\"\\n\")[0];\n\n\n for (const error of errors) {\n const toAppend = removeStacktraceNameLine(error.stack ?? \"\");\n first.stack += (addsEmptyLineAtEnd ? \"\" : \"\\n\") + separator + \"\\n\" + toAppend;\n }\n}\n\n\nexport class StackAssertionError extends Error {\n constructor(message: string, public readonly extraData?: Record<string, any> & ErrorOptions) {\n const disclaimer = `\\n\\nThis is likely an error in Stack. Please make sure you are running the newest version and report it.`;\n super(`${message}${message.endsWith(disclaimer) ? \"\" : disclaimer}`, pick(extraData ?? {}, [\"cause\"]));\n\n Object.defineProperty(this, \"customCaptureExtraArgs\", {\n get() {\n return [this.extraData];\n },\n enumerable: false,\n });\n\n if (process.env.NEXT_PUBLIC_STACK_DEBUGGER_ON_ASSERTION_ERROR === \"true\") {\n debugger;\n }\n }\n}\nStackAssertionError.prototype.name = \"StackAssertionError\";\n\n\nexport function errorToNiceString(error: unknown): string {\n if (!(error instanceof Error)) return `${typeof error}<${nicify(error)}>`;\n return nicify(error, { maxDepth: 8 });\n}\n\n\nconst errorSinks = new Set<(location: string, error: unknown, ...extraArgs: unknown[]) => void>();\nexport function registerErrorSink(sink: (location: string, error: unknown) => void): void {\n if (errorSinks.has(sink)) {\n return;\n }\n errorSinks.add(sink);\n}\nregisterErrorSink((location, error, ...extraArgs) => {\n console.error(\n `\\x1b[41mCaptured error in ${location}:`,\n // HACK: Log a nicified version of the error to get around buggy Next.js pretty-printing\n // https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button\n errorToNiceString(error),\n ...extraArgs,\n \"\\x1b[0m\",\n );\n});\nregisterErrorSink((location, error, ...extraArgs) => {\n globalVar.stackCapturedErrors = globalVar.stackCapturedErrors ?? [];\n globalVar.stackCapturedErrors.push({ location, error, extraArgs });\n});\n\n/**\n * Captures an error and sends it to the error sinks (most notably, Sentry). Errors caught with captureError are\n * supposed to be seen by an engineer, so they should be actionable and important.\n *\n * The location string is a machine-readable ID, and should hence not contain spaces or anything like that. Good\n * examples are: \"api-route-handler\", \"renderPart()\", etc.\n *\n * Errors that bubble up to the top of runAsynchronously or a route handler are already captured with captureError.\n */\nexport function captureError(location: string, error: unknown): void {\n for (const sink of errorSinks) {\n sink(\n location,\n error,\n ...error && (typeof error === 'object' || typeof error === 'function') && \"customCaptureExtraArgs\" in error && Array.isArray(error.customCaptureExtraArgs) ? (error.customCaptureExtraArgs as any[]) : [],\n );\n }\n}\n\n\ntype Status = {\n statusCode: number,\n message: string,\n};\n\ntype StatusErrorConstructorParameters =\n| [\n status: Status,\n message?: string\n]\n| [\n statusCode: number | Status,\n message: string,\n];\n\nexport class StatusError extends Error {\n private readonly __stackStatusErrorBrand = \"stack-status-error-brand-sentinel\" as const;\n public name = \"StatusError\";\n public readonly statusCode: number;\n\n public static BadRequest = { statusCode: 400, message: \"Bad Request\" };\n public static Unauthorized = { statusCode: 401, message: \"Unauthorized\" };\n public static PaymentRequired = { statusCode: 402, message: \"Payment Required\" };\n public static Forbidden = { statusCode: 403, message: \"Forbidden\" };\n public static NotFound = { statusCode: 404, message: \"Not Found\" };\n public static MethodNotAllowed = { statusCode: 405, message: \"Method Not Allowed\" };\n public static NotAcceptable = { statusCode: 406, message: \"Not Acceptable\" };\n public static ProxyAuthenticationRequired = { statusCode: 407, message: \"Proxy Authentication Required\" };\n public static RequestTimeout = { statusCode: 408, message: \"Request Timeout\" };\n public static Conflict = { statusCode: 409, message: \"Conflict\" };\n public static Gone = { statusCode: 410, message: \"Gone\" };\n public static LengthRequired = { statusCode: 411, message: \"Length Required\" };\n public static PreconditionFailed = { statusCode: 412, message: \"Precondition Failed\" };\n public static PayloadTooLarge = { statusCode: 413, message: \"Payload Too Large\" };\n public static URITooLong = { statusCode: 414, message: \"URI Too Long\" };\n public static UnsupportedMediaType = { statusCode: 415, message: \"Unsupported Media Type\" };\n public static RangeNotSatisfiable = { statusCode: 416, message: \"Range Not Satisfiable\" };\n public static ExpectationFailed = { statusCode: 417, message: \"Expectation Failed\" };\n public static ImATeapot = { statusCode: 418, message: \"I'm a teapot\" };\n public static MisdirectedRequest = { statusCode: 421, message: \"Misdirected Request\" };\n public static UnprocessableEntity = { statusCode: 422, message: \"Unprocessable Entity\" };\n public static Locked = { statusCode: 423, message: \"Locked\" };\n public static FailedDependency = { statusCode: 424, message: \"Failed Dependency\" };\n public static TooEarly = { statusCode: 425, message: \"Too Early\" };\n public static UpgradeRequired = { statusCode: 426, message: \"Upgrade Required\" };\n public static PreconditionRequired = { statusCode: 428, message: \"Precondition Required\" };\n public static TooManyRequests = { statusCode: 429, message: \"Too Many Requests\" };\n public static RequestHeaderFieldsTooLarge = { statusCode: 431, message: \"Request Header Fields Too Large\" };\n public static UnavailableForLegalReasons = { statusCode: 451, message: \"Unavailable For Legal Reasons\" };\n\n public static InternalServerError = { statusCode: 500, message: \"Internal Server Error\" };\n public static NotImplemented = { statusCode: 501, message: \"Not Implemented\" };\n public static BadGateway = { statusCode: 502, message: \"Bad Gateway\" };\n public static ServiceUnavailable = { statusCode: 503, message: \"Service Unavailable\" };\n public static GatewayTimeout = { statusCode: 504, message: \"Gateway Timeout\" };\n public static HTTPVersionNotSupported = { statusCode: 505, message: \"HTTP Version Not Supported\" };\n public static VariantAlsoNegotiates = { statusCode: 506, message: \"Variant Also Negotiates\" };\n public static InsufficientStorage = { statusCode: 507, message: \"Insufficient Storage\" };\n public static LoopDetected = { statusCode: 508, message: \"Loop Detected\" };\n public static NotExtended = { statusCode: 510, message: \"Not Extended\" };\n public static NetworkAuthenticationRequired = { statusCode: 511, message: \"Network Authentication Required\" };\n\n\n constructor(...args: StatusErrorConstructorParameters);\n constructor(\n status: number | Status,\n message?: string,\n ) {\n if (typeof status === \"object\") {\n message ??= status.message;\n status = status.statusCode;\n }\n super(message);\n this.statusCode = status;\n if (!message) {\n throw new StackAssertionError(\"StatusError always requires a message unless a Status object is passed\", { cause: this });\n }\n }\n\n public static isStatusError(error: unknown): error is StatusError {\n // like instanceof, but also works for errors thrown in other realms or by different versions of the same package\n return typeof error === \"object\" && error !== null && \"__stackStatusErrorBrand\" in error && error.__stackStatusErrorBrand === \"stack-status-error-brand-sentinel\";\n }\n\n public isClientError() {\n return this.statusCode >= 400 && this.statusCode < 500;\n }\n\n public isServerError() {\n return !this.isClientError();\n }\n\n public getStatusCode(): number {\n return this.statusCode;\n }\n\n public getBody(): Uint8Array {\n return new TextEncoder().encode(this.message);\n }\n\n public getHeaders(): Record<string, string[]> {\n return {\n \"Content-Type\": [\"text/plain; charset=utf-8\"],\n };\n }\n\n public toDescriptiveJson(): Json {\n return {\n status_code: this.getStatusCode(),\n message: this.message,\n headers: this.getHeaders(),\n };\n }\n\n /**\n * @deprecated this is not a good way to make status errors human-readable, use toDescriptiveJson instead\n */\n public toHttpJson(): Json {\n return {\n status_code: this.statusCode,\n body: this.message,\n headers: this.getHeaders(),\n };\n }\n}\nStatusError.prototype.name = \"StatusError\";\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/errors.tsx"],"sourcesContent":["import { globalVar } from \"./globals\";\nimport { Json } from \"./json\";\nimport { pick } from \"./objects\";\nimport { nicify } from \"./strings\";\n\n\nexport function throwErr(errorMessage: string, extraData?: any): never;\nexport function throwErr(error: Error): never;\nexport function throwErr(...args: StatusErrorConstructorParameters): never;\nexport function throwErr(...args: any[]): never {\n if (typeof args[0] === \"string\") {\n throw new StackAssertionError(args[0], args[1]);\n } else if (args[0] instanceof Error) {\n throw args[0];\n } else {\n // @ts-expect-error\n throw new StatusError(...args);\n }\n}\n\nfunction removeStacktraceNameLine(stack: string): string {\n // some browsers (eg. Chrome) prepend the stack with an extra line with the error name\n const addsNameLine = new Error().stack?.startsWith(\"Error\\n\");\n return stack.split(\"\\n\").slice(addsNameLine ? 1 : 0).join(\"\\n\");\n}\n\n\n/**\n * Concatenates the (original) stacktraces of the given errors onto the first.\n *\n * Note: Very often, the concatStacktracesIfRejected function in promises.tsx is an easier way to use this function.\n *\n * Useful when you invoke an async function to receive a promise without awaiting it immediately. Browsers are smart\n * enough to keep track of the call stack in async function calls when you invoke `.then` within the same async tick,\n * but if you don't, the stacktrace will be lost.\n *\n * Here's an example of the unwanted behavior:\n *\n * ```tsx\n * async function log() {\n * await wait(0); // put the task on the event loop\n * console.log(new Error().stack);\n * }\n *\n * async function main() {\n * await log(); // good; prints both \"log\" and \"main\" on the stacktrace\n * log(); // bad; prints only \"log\" on the stacktrace\n * }\n * ```\n */\nexport function concatStacktraces(first: Error, ...errors: Error[]): void {\n // some browsers (eg. Firefox) add an extra empty line at the end\n const addsEmptyLineAtEnd = first.stack?.endsWith(\"\\n\");\n\n\n // Add a reference to this function itself so that we know that stacktraces were concatenated\n // If you are coming here from a stacktrace, please know that the two parts before and after this line are different\n // stacktraces that were concatenated with concatStacktraces\n const separator = removeStacktraceNameLine(new Error().stack ?? \"\").split(\"\\n\")[0];\n\n\n for (const error of errors) {\n const toAppend = removeStacktraceNameLine(error.stack ?? \"\");\n first.stack += (addsEmptyLineAtEnd ? \"\" : \"\\n\") + separator + \"\\n\" + toAppend;\n }\n}\n\n\nexport class StackAssertionError extends Error {\n constructor(message: string, public readonly extraData?: Record<string, any> & ErrorOptions) {\n const disclaimer = `\\n\\nThis is likely an error in Stack. Please make sure you are running the newest version and report it.`;\n super(`${message}${message.endsWith(disclaimer) ? \"\" : disclaimer}`, pick(extraData ?? {}, [\"cause\"]));\n\n Object.defineProperty(this, \"customCaptureExtraArgs\", {\n get() {\n return [this.extraData];\n },\n enumerable: false,\n });\n\n if (process.env.NEXT_PUBLIC_STACK_DEBUGGER_ON_ASSERTION_ERROR === \"true\") {\n debugger;\n }\n }\n}\nStackAssertionError.prototype.name = \"StackAssertionError\";\n\n\nexport function errorToNiceString(error: unknown): string {\n if (!(error instanceof Error)) return `${typeof error}<${nicify(error)}>`;\n return nicify(error, { maxDepth: 8 });\n}\n\n\nconst errorSinks = new Set<(location: string, error: unknown, ...extraArgs: unknown[]) => void>();\nexport function registerErrorSink(sink: (location: string, error: unknown) => void): void {\n if (errorSinks.has(sink)) {\n return;\n }\n errorSinks.add(sink);\n}\nregisterErrorSink((location, error, ...extraArgs) => {\n console.error(\n `\\x1b[41mCaptured error in ${location}:`,\n // HACK: Log a nicified version of the error to get around buggy Next.js pretty-printing\n // https://www.reddit.com/r/nextjs/comments/1gkxdqe/comment/m19kxgn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button\n errorToNiceString(error),\n ...extraArgs,\n \"\\x1b[0m\",\n );\n});\nregisterErrorSink((location, error, ...extraArgs) => {\n globalVar.stackCapturedErrors = globalVar.stackCapturedErrors ?? [];\n globalVar.stackCapturedErrors.push({ location, error, extraArgs });\n});\n\n/**\n * Captures an error and sends it to the error sinks (most notably, Sentry). Errors caught with captureError are\n * supposed to be seen by an engineer, so they should be actionable and important.\n *\n * The location string is a machine-readable ID, and should hence not contain spaces or anything like that. Good\n * examples are: \"api-route-handler\", \"renderPart()\", etc.\n *\n * Errors that bubble up to the top of runAsynchronously or a route handler are already captured with captureError.\n */\nexport function captureError(location: string, error: unknown): void {\n for (const sink of errorSinks) {\n sink(\n location,\n error,\n ...error && (typeof error === 'object' || typeof error === 'function') && \"customCaptureExtraArgs\" in error && Array.isArray(error.customCaptureExtraArgs) ? (error.customCaptureExtraArgs as any[]) : [],\n );\n }\n}\n\n\ntype Status = {\n statusCode: number,\n message: string,\n};\n\ntype StatusErrorConstructorParameters =\n| [\n status: Status,\n message?: string\n]\n| [\n statusCode: number | Status,\n message: string,\n];\n\nexport class StatusError extends Error {\n private readonly __stackStatusErrorBrand = \"stack-status-error-brand-sentinel\" as const;\n public name = \"StatusError\";\n public readonly statusCode: number;\n\n public static BadRequest = { statusCode: 400, message: \"Bad Request\" };\n public static Unauthorized = { statusCode: 401, message: \"Unauthorized\" };\n public static PaymentRequired = { statusCode: 402, message: \"Payment Required\" };\n public static Forbidden = { statusCode: 403, message: \"Forbidden\" };\n public static NotFound = { statusCode: 404, message: \"Not Found\" };\n public static MethodNotAllowed = { statusCode: 405, message: \"Method Not Allowed\" };\n public static NotAcceptable = { statusCode: 406, message: \"Not Acceptable\" };\n public static ProxyAuthenticationRequired = { statusCode: 407, message: \"Proxy Authentication Required\" };\n public static RequestTimeout = { statusCode: 408, message: \"Request Timeout\" };\n public static Conflict = { statusCode: 409, message: \"Conflict\" };\n public static Gone = { statusCode: 410, message: \"Gone\" };\n public static LengthRequired = { statusCode: 411, message: \"Length Required\" };\n public static PreconditionFailed = { statusCode: 412, message: \"Precondition Failed\" };\n public static PayloadTooLarge = { statusCode: 413, message: \"Payload Too Large\" };\n public static URITooLong = { statusCode: 414, message: \"URI Too Long\" };\n public static UnsupportedMediaType = { statusCode: 415, message: \"Unsupported Media Type\" };\n public static RangeNotSatisfiable = { statusCode: 416, message: \"Range Not Satisfiable\" };\n public static ExpectationFailed = { statusCode: 417, message: \"Expectation Failed\" };\n public static ImATeapot = { statusCode: 418, message: \"I'm a teapot\" };\n public static MisdirectedRequest = { statusCode: 421, message: \"Misdirected Request\" };\n public static UnprocessableEntity = { statusCode: 422, message: \"Unprocessable Entity\" };\n public static Locked = { statusCode: 423, message: \"Locked\" };\n public static FailedDependency = { statusCode: 424, message: \"Failed Dependency\" };\n public static TooEarly = { statusCode: 425, message: \"Too Early\" };\n public static UpgradeRequired = { statusCode: 426, message: \"Upgrade Required\" };\n public static PreconditionRequired = { statusCode: 428, message: \"Precondition Required\" };\n public static TooManyRequests = { statusCode: 429, message: \"Too Many Requests\" };\n public static RequestHeaderFieldsTooLarge = { statusCode: 431, message: \"Request Header Fields Too Large\" };\n public static UnavailableForLegalReasons = { statusCode: 451, message: \"Unavailable For Legal Reasons\" };\n\n public static InternalServerError = { statusCode: 500, message: \"Internal Server Error\" };\n public static NotImplemented = { statusCode: 501, message: \"Not Implemented\" };\n public static BadGateway = { statusCode: 502, message: \"Bad Gateway\" };\n public static ServiceUnavailable = { statusCode: 503, message: \"Service Unavailable\" };\n public static GatewayTimeout = { statusCode: 504, message: \"Gateway Timeout\" };\n public static HTTPVersionNotSupported = { statusCode: 505, message: \"HTTP Version Not Supported\" };\n public static VariantAlsoNegotiates = { statusCode: 506, message: \"Variant Also Negotiates\" };\n public static InsufficientStorage = { statusCode: 507, message: \"Insufficient Storage\" };\n public static LoopDetected = { statusCode: 508, message: \"Loop Detected\" };\n public static NotExtended = { statusCode: 510, message: \"Not Extended\" };\n public static NetworkAuthenticationRequired = { statusCode: 511, message: \"Network Authentication Required\" };\n\n\n constructor(...args: StatusErrorConstructorParameters);\n constructor(\n status: number | Status,\n message?: string,\n ) {\n if (typeof status === \"object\") {\n message ??= status.message;\n status = status.statusCode;\n }\n super(message);\n this.statusCode = status;\n if (!message) {\n throw new StackAssertionError(\"StatusError always requires a message unless a Status object is passed\", { cause: this });\n }\n }\n\n public static isStatusError(error: unknown): error is StatusError {\n // like instanceof, but also works for errors thrown in other realms or by different versions of the same package\n return typeof error === \"object\" && error !== null && \"__stackStatusErrorBrand\" in error && error.__stackStatusErrorBrand === \"stack-status-error-brand-sentinel\";\n }\n\n public isClientError() {\n return this.statusCode >= 400 && this.statusCode < 500;\n }\n\n public isServerError() {\n return !this.isClientError();\n }\n\n public getStatusCode(): number {\n return this.statusCode;\n }\n\n public getBody(): Uint8Array {\n return new TextEncoder().encode(this.message);\n }\n\n public getHeaders(): Record<string, string[]> {\n return {\n \"Content-Type\": [\"text/plain; charset=utf-8\"],\n };\n }\n\n public toDescriptiveJson(): Json {\n return {\n status_code: this.getStatusCode(),\n message: this.message,\n headers: this.getHeaders(),\n };\n }\n\n /**\n * @deprecated this is not a good way to make status errors human-readable, use toDescriptiveJson instead\n */\n public toHttpJson(): Json {\n return {\n status_code: this.statusCode,\n body: this.message,\n headers: this.getHeaders(),\n };\n }\n}\nStatusError.prototype.name = \"StatusError\";\n"],"mappings":"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","names":[]}
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
// src/utils/esbuild.tsx
|
|
2
2
|
import * as esbuild from "esbuild-wasm/lib/browser.js";
|
|
3
3
|
import { join } from "path";
|
|
4
|
+
import { isBrowserLike } from "./env.js";
|
|
4
5
|
import { StackAssertionError, throwErr } from "./errors.js";
|
|
5
6
|
import { Result } from "./results.js";
|
|
6
|
-
import {
|
|
7
|
+
import { traceSpan, withTraceSpan } from "./telemetry.js";
|
|
8
|
+
var esbuildWasmUrl = `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`;
|
|
7
9
|
var esbuildInitializePromise = null;
|
|
8
10
|
globalThis.self ??= globalThis;
|
|
9
|
-
|
|
11
|
+
function initializeEsbuild() {
|
|
10
12
|
if (!esbuildInitializePromise) {
|
|
11
|
-
esbuildInitializePromise =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
esbuildInitializePromise = withTraceSpan("initializeEsbuild", async () => {
|
|
14
|
+
await esbuild.initialize(isBrowserLike() ? {
|
|
15
|
+
wasmURL: esbuildWasmUrl
|
|
16
|
+
} : {
|
|
17
|
+
wasmModule: await fetch(esbuildWasmUrl).then((wasm) => wasm.arrayBuffer()).then((wasm) => new WebAssembly.Module(wasm)),
|
|
18
|
+
worker: false
|
|
19
|
+
});
|
|
20
|
+
})();
|
|
17
21
|
}
|
|
18
|
-
|
|
22
|
+
return esbuildInitializePromise;
|
|
19
23
|
}
|
|
20
24
|
async function bundleJavaScript(sourceFiles, options = {}) {
|
|
21
25
|
await initializeEsbuild();
|
|
@@ -32,7 +36,7 @@ async function bundleJavaScript(sourceFiles, options = {}) {
|
|
|
32
36
|
]);
|
|
33
37
|
let result;
|
|
34
38
|
try {
|
|
35
|
-
result = await esbuild.build({
|
|
39
|
+
result = await traceSpan("bundleJavaScript", async () => await esbuild.build({
|
|
36
40
|
entryPoints: ["/entry.js"],
|
|
37
41
|
bundle: true,
|
|
38
42
|
write: false,
|
|
@@ -82,7 +86,7 @@ async function bundleJavaScript(sourceFiles, options = {}) {
|
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
]
|
|
85
|
-
});
|
|
89
|
+
}));
|
|
86
90
|
} catch (e) {
|
|
87
91
|
if (e instanceof Error && e.message.startsWith("Build failed with ")) {
|
|
88
92
|
return Result.error(e.message);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/esbuild.tsx"],"sourcesContent":["import * as esbuild from 'esbuild-wasm/lib/browser.js';\nimport { join } from 'path';\nimport { StackAssertionError, throwErr } from \"./errors\";\nimport { Result } from \"./results\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/esbuild.tsx"],"sourcesContent":["import * as esbuild from 'esbuild-wasm/lib/browser.js';\nimport { join } from 'path';\nimport { isBrowserLike } from './env';\nimport { StackAssertionError, throwErr } from \"./errors\";\nimport { Result } from \"./results\";\nimport { traceSpan, withTraceSpan } from './telemetry';\n\nconst esbuildWasmUrl = `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`;\n\nlet esbuildInitializePromise: Promise<void> | null = null;\n// esbuild requires self property to be set, and it is not set by default in nodejs\n(globalThis.self as any) ??= globalThis as any;\n\nexport function initializeEsbuild(): Promise<void> {\n if (!esbuildInitializePromise) {\n esbuildInitializePromise = withTraceSpan('initializeEsbuild', async () => {\n await esbuild.initialize(isBrowserLike() ? {\n wasmURL: esbuildWasmUrl,\n } : {\n wasmModule: (\n await fetch(esbuildWasmUrl)\n .then(wasm => wasm.arrayBuffer())\n .then(wasm => new WebAssembly.Module(wasm))\n ),\n worker: false,\n });\n })();\n }\n\n return esbuildInitializePromise;\n}\n\nexport async function bundleJavaScript(sourceFiles: Record<string, string> & { '/entry.js': string }, options: {\n format?: 'iife' | 'esm' | 'cjs',\n externalPackages?: Record<string, string>,\n keepAsImports?: string[],\n sourcemap?: false | 'inline',\n} = {}): Promise<Result<string, string>> {\n await initializeEsbuild();\n\n const sourceFilesMap = new Map(Object.entries(sourceFiles));\n const externalPackagesMap = new Map(Object.entries(options.externalPackages ?? {}));\n const keepAsImports = options.keepAsImports ?? [];\n\n const extToLoader: Map<string, esbuild.Loader> = new Map([\n ['tsx', 'tsx'],\n ['ts', 'ts'],\n ['js', 'js'],\n ['jsx', 'jsx'],\n ['json', 'json'],\n ['css', 'css'],\n ]);\n let result;\n try {\n result = await traceSpan('bundleJavaScript', async () => await esbuild.build({\n entryPoints: ['/entry.js'],\n bundle: true,\n write: false,\n format: options.format ?? 'iife',\n platform: 'browser',\n target: 'es2015',\n jsx: 'automatic',\n sourcemap: options.sourcemap ?? 'inline',\n external: keepAsImports,\n plugins: [\n {\n name: 'replace-packages-with-globals',\n setup(build) {\n build.onResolve({ filter: /.*/ }, args => {\n // Skip packages that should remain external (not be shimmed)\n if (keepAsImports.includes(args.path)) {\n return undefined;\n }\n if (externalPackagesMap.has(args.path)) {\n return { path: args.path, namespace: 'package-shim' };\n }\n return undefined;\n });\n\n build.onLoad({ filter: /.*/, namespace: 'package-shim' }, (args) => {\n const contents = externalPackagesMap.get(args.path);\n if (contents == null) throw new StackAssertionError(`esbuild requested file ${args.path} that is not in the virtual file system`);\n\n return { contents, loader: 'ts' };\n });\n },\n },\n {\n name: 'virtual-fs',\n setup(build) {\n build.onResolve({ filter: /.*/ }, args => {\n const absolutePath = join(\"/\", args.path);\n if (sourceFilesMap.has(absolutePath)) {\n return { path: absolutePath, namespace: 'virtual' };\n }\n return undefined;\n });\n\n /* 2️⃣ Load the module from the map */\n build.onLoad({ filter: /.*/, namespace: 'virtual' }, args => {\n const contents = sourceFilesMap.get(args.path);\n if (contents == null) throw new StackAssertionError(`esbuild requested file ${args.path} that is not in the virtual file system`);\n\n const ext = args.path.split('.').pop() ?? '';\n const loader = extToLoader.get(ext) ?? throwErr(`esbuild requested file ${args.path} with unknown extension ${ext}`);\n\n return { contents, loader };\n });\n },\n },\n ],\n }));\n } catch (e) {\n if (e instanceof Error && e.message.startsWith(\"Build failed with \")) {\n return Result.error(e.message);\n }\n throw e;\n }\n\n if (result.errors.length > 0) {\n return Result.error(result.errors.map(e => e.text).join('\\n'));\n }\n\n if (result.outputFiles.length > 0) {\n return Result.ok(result.outputFiles[0].text);\n }\n return throwErr(\"No output generated??\");\n}\n"],"mappings":"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","names":["build"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/utils/promises.tsx
|
|
2
2
|
import { KnownError } from "../index.js";
|
|
3
|
-
import { StackAssertionError, captureError, concatStacktraces } from "./errors.js";
|
|
3
|
+
import { StackAssertionError, captureError, concatStacktraces, errorToNiceString } from "./errors.js";
|
|
4
4
|
import { DependenciesMap } from "./maps.js";
|
|
5
5
|
import { Result } from "./results.js";
|
|
6
6
|
import { generateUuid } from "./uuids.js";
|
|
@@ -83,6 +83,15 @@ function ignoreUnhandledRejection(promise) {
|
|
|
83
83
|
promise.catch(() => {
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
|
+
function concatStacktracesIfRejected(promise) {
|
|
87
|
+
const currentError = new Error();
|
|
88
|
+
promise.catch((error) => {
|
|
89
|
+
if (error instanceof Error) {
|
|
90
|
+
concatStacktraces(error, currentError);
|
|
91
|
+
} else {
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
86
95
|
async function wait(ms) {
|
|
87
96
|
if (!Number.isFinite(ms) || ms < 0) {
|
|
88
97
|
throw new StackAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);
|
|
@@ -118,18 +127,19 @@ function runAsynchronously(promiseOrFunc, options = {}) {
|
|
|
118
127
|
if (typeof promiseOrFunc === "function") {
|
|
119
128
|
promiseOrFunc = promiseOrFunc();
|
|
120
129
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
if (promiseOrFunc) {
|
|
131
|
+
concatStacktracesIfRejected(promiseOrFunc);
|
|
132
|
+
promiseOrFunc.catch((error) => {
|
|
133
|
+
options.onError?.(error);
|
|
134
|
+
const newError = new StackAssertionError(
|
|
135
|
+
"Uncaught error in asynchronous function: " + errorToNiceString(error),
|
|
136
|
+
{ cause: error }
|
|
137
|
+
);
|
|
138
|
+
if (!options.noErrorLogging) {
|
|
139
|
+
captureError("runAsynchronously", newError);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
133
143
|
}
|
|
134
144
|
var TimeoutError = class extends Error {
|
|
135
145
|
constructor(ms) {
|
|
@@ -215,6 +225,7 @@ function throttled(func, delayMs) {
|
|
|
215
225
|
};
|
|
216
226
|
}
|
|
217
227
|
export {
|
|
228
|
+
concatStacktracesIfRejected,
|
|
218
229
|
createPromise,
|
|
219
230
|
ignoreUnhandledRejection,
|
|
220
231
|
neverResolve,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/promises.tsx"],"sourcesContent":["import { KnownError } from \"..\";\nimport { StackAssertionError, captureError, concatStacktraces } from \"./errors\";\nimport { DependenciesMap } from \"./maps\";\nimport { Result } from \"./results\";\nimport { generateUuid } from \"./uuids\";\n\nexport type ReactPromise<T> = Promise<T> & (\n | { status: \"rejected\", reason: unknown }\n | { status: \"fulfilled\", value: T }\n | { status: \"pending\" }\n);\n\ntype Resolve<T> = (value: T) => void;\ntype Reject = (reason: unknown) => void;\nexport function createPromise<T>(callback: (resolve: Resolve<T>, reject: Reject) => void): ReactPromise<T> {\n let status = \"pending\" as \"fulfilled\" | \"rejected\" | \"pending\";\n let valueOrReason: T | unknown | undefined = undefined;\n let resolve: Resolve<T> | null = null;\n let reject: Reject | null = null;\n const promise = new Promise<T>((res, rej) => {\n resolve = (value) => {\n if (status !== \"pending\") return;\n status = \"fulfilled\";\n valueOrReason = value;\n res(value);\n };\n reject = (reason) => {\n if (status !== \"pending\") return;\n status = \"rejected\";\n valueOrReason = reason;\n rej(reason);\n };\n });\n\n callback(resolve!, reject!);\n return Object.assign(promise, {\n status: status,\n ...status === \"fulfilled\" ? { value: valueOrReason as T } : {},\n ...status === \"rejected\" ? { reason: valueOrReason } : {},\n } as any);\n}\nundefined?.test(\"createPromise\", async ({ expect }) => {\n // Test resolved promise\n const resolvedPromise = createPromise<number>((resolve) => {\n resolve(42);\n });\n expect(resolvedPromise.status).toBe(\"fulfilled\");\n expect((resolvedPromise as any).value).toBe(42);\n expect(await resolvedPromise).toBe(42);\n\n // Test rejected promise\n const error = new Error(\"Test error\");\n const rejectedPromise = createPromise<number>((_, reject) => {\n reject(error);\n });\n expect(rejectedPromise.status).toBe(\"rejected\");\n expect((rejectedPromise as any).reason).toBe(error);\n await expect(rejectedPromise).rejects.toBe(error);\n\n // Test pending promise\n const pendingPromise = createPromise<number>(() => {\n // Do nothing, leave it pending\n });\n expect(pendingPromise.status).toBe(\"pending\");\n expect((pendingPromise as any).value).toBeUndefined();\n expect((pendingPromise as any).reason).toBeUndefined();\n\n // Test that resolving after already resolved does nothing\n let resolveCount = 0;\n const multiResolvePromise = createPromise<number>((resolve) => {\n resolve(1);\n resolveCount++;\n resolve(2);\n resolveCount++;\n });\n expect(resolveCount).toBe(2); // Both resolve calls executed\n expect(multiResolvePromise.status).toBe(\"fulfilled\");\n expect((multiResolvePromise as any).value).toBe(1); // Only first resolve took effect\n expect(await multiResolvePromise).toBe(1);\n});\n\nlet resolvedCache: DependenciesMap<[unknown], ReactPromise<unknown>> | null = null;\n/**\n * Like Promise.resolve(...), but also adds the status and value properties for use with React's `use` hook, and caches\n * the value so that invoking `resolved` twice returns the same promise.\n */\nexport function resolved<T>(value: T): ReactPromise<T> {\n resolvedCache ??= new DependenciesMap<[unknown], ReactPromise<unknown>>();\n if (resolvedCache.has([value])) {\n return resolvedCache.get([value]) as ReactPromise<T>;\n }\n\n const res = Object.assign(Promise.resolve(value), {\n status: \"fulfilled\",\n value,\n } as const);\n resolvedCache.set([value], res);\n return res;\n}\nundefined?.test(\"resolved\", async ({ expect }) => {\n // Test with primitive value\n const promise1 = resolved(42);\n expect(promise1.status).toBe(\"fulfilled\");\n // Need to use type assertion since value is only available when status is \"fulfilled\"\n expect((promise1 as { value: number }).value).toBe(42);\n expect(await promise1).toBe(42);\n\n // Test with object value\n const obj = { test: true };\n const promise2 = resolved(obj);\n expect(promise2.status).toBe(\"fulfilled\");\n expect((promise2 as { value: typeof obj }).value).toBe(obj);\n expect(await promise2).toBe(obj);\n\n // Test caching (same reference for same value)\n const promise3 = resolved(42);\n expect(promise3).toBe(promise1); // Same reference due to caching\n\n // Test with different value (different reference)\n const promise4 = resolved(43);\n expect(promise4).not.toBe(promise1);\n});\n\nlet rejectedCache: DependenciesMap<[unknown], ReactPromise<unknown>> | null = null;\n/**\n * Like Promise.reject(...), but also adds the status and value properties for use with React's `use` hook, and caches\n * the value so that invoking `rejected` twice returns the same promise.\n */\nexport function rejected<T>(reason: unknown): ReactPromise<T> {\n rejectedCache ??= new DependenciesMap<[unknown], ReactPromise<unknown>>();\n if (rejectedCache.has([reason])) {\n return rejectedCache.get([reason]) as ReactPromise<T>;\n }\n\n const promise = Promise.reject(reason);\n ignoreUnhandledRejection(promise);\n const res = Object.assign(promise, {\n status: \"rejected\",\n reason: reason,\n } as const);\n rejectedCache.set([reason], res);\n return res;\n}\nundefined?.test(\"rejected\", ({ expect }) => {\n // Test with error object\n const error = new Error(\"Test error\");\n const promise1 = rejected<number>(error);\n expect(promise1.status).toBe(\"rejected\");\n // Need to use type assertion since reason is only available when status is \"rejected\"\n expect((promise1 as { reason: Error }).reason).toBe(error);\n\n // Test with string reason\n const promise2 = rejected<string>(\"error message\");\n expect(promise2.status).toBe(\"rejected\");\n expect((promise2 as { reason: string }).reason).toBe(\"error message\");\n\n // Test caching (same reference for same reason)\n const promise3 = rejected<number>(error);\n expect(promise3).toBe(promise1); // Same reference due to caching\n\n // Test with different reason (different reference)\n const differentError = new Error(\"Different error\");\n const promise4 = rejected<number>(differentError);\n expect(promise4).not.toBe(promise1);\n\n // Note: We're not using await expect(promise).rejects to avoid unhandled rejections\n});\n\n// We'll skip the rejection test for pending() since it's causing unhandled rejections\n// The function is already well tested through other tests like rejected() and createPromise()\n\n\nconst neverResolvePromise = pending(new Promise<never>(() => {}));\nexport function neverResolve(): ReactPromise<never> {\n return neverResolvePromise;\n}\nundefined?.test(\"neverResolve\", ({ expect }) => {\n const promise = neverResolve();\n expect(promise.status).toBe(\"pending\");\n expect((promise as any).value).toBeUndefined();\n expect((promise as any).reason).toBeUndefined();\n\n // Test that multiple calls return the same promise\n const promise2 = neverResolve();\n expect(promise2).toBe(promise);\n});\n\nexport function pending<T>(promise: Promise<T>, options: { disableErrorWrapping?: boolean } = {}): ReactPromise<T> {\n const res = promise.then(\n value => {\n res.status = \"fulfilled\";\n (res as any).value = value;\n return value;\n },\n actualReason => {\n res.status = \"rejected\";\n (res as any).reason = actualReason;\n throw actualReason;\n },\n ) as ReactPromise<T>;\n res.status = \"pending\";\n return res;\n}\nundefined?.test(\"pending\", async ({ expect }) => {\n // Test with a promise that resolves\n const resolvePromise = Promise.resolve(42);\n const pendingPromise = pending(resolvePromise);\n\n // Initially it should be pending\n expect(pendingPromise.status).toBe(\"pending\");\n\n // After resolution, it should be fulfilled\n await resolvePromise;\n // Need to wait a tick for the then handler to execute\n await new Promise(resolve => setTimeout(resolve, 0));\n expect(pendingPromise.status).toBe(\"fulfilled\");\n expect((pendingPromise as { value: number }).value).toBe(42);\n\n // For the rejection test, we'll use a separate test to avoid unhandled rejections\n});\n\n/**\n * Should be used to wrap Promises that are not immediately awaited, so they don't throw an unhandled promise rejection\n * error.\n *\n * Vercel kills serverless functions on unhandled promise rejection errors, so this is important.\n */\nexport function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): void {\n promise.catch(() => {});\n}\nundefined?.test(\"ignoreUnhandledRejection\", async ({ expect }) => {\n // Test with a promise that resolves\n const resolvePromise = Promise.resolve(42);\n ignoreUnhandledRejection(resolvePromise);\n expect(await resolvePromise).toBe(42); // Should still resolve to the same value\n\n // Test with a promise that rejects\n // The promise should still reject, but the rejection is caught internally\n // so it doesn't cause an unhandled rejection error\n const error = new Error(\"Test error\");\n const rejectPromise = Promise.reject(error);\n ignoreUnhandledRejection(rejectPromise);\n await expect(rejectPromise).rejects.toBe(error);\n});\n\nexport async function wait(ms: number) {\n if (!Number.isFinite(ms) || ms < 0) {\n throw new StackAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);\n }\n if (ms >= 2**31) {\n throw new StackAssertionError(\"The maximum timeout for wait() is 2147483647ms (2**31 - 1). (found: ${ms}ms)\");\n }\n return await new Promise<void>(resolve => setTimeout(resolve, ms));\n}\nundefined?.test(\"wait\", async ({ expect }) => {\n // Test with valid input\n const start = Date.now();\n await wait(10);\n const elapsed = Date.now() - start;\n expect(elapsed).toBeGreaterThanOrEqual(5); // Allow some flexibility in timing\n\n // Test with zero\n await expect(wait(0)).resolves.toBeUndefined();\n\n // Test with negative number\n await expect(wait(-10)).rejects.toThrow(\"wait() requires a non-negative integer\");\n\n // Test with non-finite number\n await expect(wait(NaN)).rejects.toThrow(\"wait() requires a non-negative integer\");\n await expect(wait(Infinity)).rejects.toThrow(\"wait() requires a non-negative integer\");\n\n // Test with too large number\n await expect(wait(2**31)).rejects.toThrow(\"The maximum timeout for wait()\");\n});\n\nexport async function waitUntil(date: Date) {\n return await wait(date.getTime() - Date.now());\n}\nundefined?.test(\"waitUntil\", async ({ expect }) => {\n // Test with future date\n const futureDate = new Date(Date.now() + 10);\n const start = Date.now();\n await waitUntil(futureDate);\n const elapsed = Date.now() - start;\n expect(elapsed).toBeGreaterThanOrEqual(5); // Allow some flexibility in timing\n\n // Test with past date - this will throw because wait() requires non-negative time\n // We need to verify it throws the correct error\n try {\n await waitUntil(new Date(Date.now() - 1000));\n expect.fail(\"Should have thrown an error\");\n } catch (error) {\n expect(error).toBeInstanceOf(StackAssertionError);\n expect((error as Error).message).toContain(\"wait() requires a non-negative integer\");\n }\n});\n\nexport function runAsynchronouslyWithAlert(...args: Parameters<typeof runAsynchronously>) {\n return runAsynchronously(\n args[0],\n {\n ...args[1],\n onError: error => {\n if (KnownError.isKnownError(error) && typeof process !== \"undefined\" && (process.env.NODE_ENV as any)?.includes(\"production\")) {\n alert(error.message);\n } else {\n alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === \"development\" ? `check the browser console for the full error.` : \"report this to the developer.\"}\\n\\n${error}`);\n }\n args[1]?.onError?.(error);\n },\n },\n ...args.slice(2) as [],\n );\n}\nundefined?.test(\"runAsynchronouslyWithAlert\", ({ expect }) => {\n // Simple test to verify the function calls runAsynchronously\n // We can't easily test the alert functionality without mocking\n const testFn = () => Promise.resolve(\"test\");\n const testOptions = { noErrorLogging: true };\n\n // Just verify it doesn't throw\n expect(() => runAsynchronouslyWithAlert(testFn, testOptions)).not.toThrow();\n\n // We can't easily test the error handling without mocking, so we'll\n // just verify the function exists and can be called\n expect(typeof runAsynchronouslyWithAlert).toBe(\"function\");\n});\n\nexport function runAsynchronously(\n promiseOrFunc: void | Promise<unknown> | (() => void | Promise<unknown>) | undefined,\n options: {\n noErrorLogging?: boolean,\n onError?: (error: Error) => void,\n } = {},\n): void {\n if (typeof promiseOrFunc === \"function\") {\n promiseOrFunc = promiseOrFunc();\n }\n const duringError = new Error();\n promiseOrFunc?.catch(error => {\n options.onError?.(error);\n const newError = new StackAssertionError(\n \"Uncaught error in asynchronous function: \" + error.toString(),\n { cause: error },\n );\n concatStacktraces(newError, duringError);\n if (!options.noErrorLogging) {\n captureError(\"runAsynchronously\", newError);\n }\n });\n}\nundefined?.test(\"runAsynchronously\", ({ expect }) => {\n // Simple test to verify the function exists and can be called\n const testFn = () => Promise.resolve(\"test\");\n\n // Just verify it doesn't throw\n expect(() => runAsynchronously(testFn)).not.toThrow();\n expect(() => runAsynchronously(Promise.resolve(\"test\"))).not.toThrow();\n expect(() => runAsynchronously(undefined)).not.toThrow();\n\n // We can't easily test the error handling without mocking, so we'll\n // just verify the function exists and can be called with options\n expect(() => runAsynchronously(testFn, { noErrorLogging: true })).not.toThrow();\n expect(() => runAsynchronously(testFn, { onError: () => {} })).not.toThrow();\n});\n\n\nclass TimeoutError extends Error {\n constructor(public readonly ms: number) {\n super(`Timeout after ${ms}ms`);\n this.name = \"TimeoutError\";\n }\n}\n\nexport async function timeout<T>(promise: Promise<T>, ms: number): Promise<Result<T, TimeoutError>> {\n return await Promise.race([\n promise.then(value => Result.ok(value)),\n wait(ms).then(() => Result.error(new TimeoutError(ms))),\n ]);\n}\nundefined?.test(\"timeout\", async ({ expect }) => {\n // Test with a promise that resolves quickly\n const fastPromise = Promise.resolve(42);\n const fastResult = await timeout(fastPromise, 100);\n expect(fastResult.status).toBe(\"ok\");\n if (fastResult.status === \"ok\") {\n expect(fastResult.data).toBe(42);\n }\n\n // Test with a promise that takes longer than the timeout\n const slowPromise = new Promise(resolve => setTimeout(() => resolve(\"too late\"), 50));\n const slowResult = await timeout(slowPromise, 10);\n expect(slowResult.status).toBe(\"error\");\n if (slowResult.status === \"error\") {\n expect(slowResult.error).toBeInstanceOf(TimeoutError);\n expect((slowResult.error as TimeoutError).ms).toBe(10);\n }\n});\n\nexport async function timeoutThrow<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Result.orThrow(await timeout(promise, ms));\n}\nundefined?.test(\"timeoutThrow\", async ({ expect }) => {\n // Test with a promise that resolves quickly\n const fastPromise = Promise.resolve(42);\n const fastResult = await timeoutThrow(fastPromise, 100);\n expect(fastResult).toBe(42);\n\n // Test with a promise that takes longer than the timeout\n const slowPromise = new Promise(resolve => setTimeout(() => resolve(\"too late\"), 50));\n await expect(timeoutThrow(slowPromise, 10)).rejects.toThrow(\"Timeout after 10ms\");\n await expect(timeoutThrow(slowPromise, 10)).rejects.toBeInstanceOf(TimeoutError);\n});\n\n\nexport type RateLimitOptions = {\n /**\n * The number of requests to process in parallel. Currently only 1 is supported.\n */\n concurrency: 1,\n\n /**\n * If true, multiple requests waiting at the same time will be reduced to just one. Default is false.\n */\n batchCalls?: boolean,\n\n /**\n * Waits for throttleMs since the start of last request before starting the next request. Default is 0.\n */\n throttleMs?: number,\n\n /**\n * Waits for gapMs since the end of last request before starting the next request. Default is 0.\n */\n gapMs?: number,\n\n /**\n * Waits until there have been no new requests for debounceMs before starting a new request. Default is 0.\n */\n debounceMs?: number,\n};\n\nexport function rateLimited<T>(\n func: () => Promise<T>,\n options: RateLimitOptions,\n): () => Promise<T> {\n let waitUntil = performance.now();\n let queue: [(t: T) => void, (e: unknown) => void][] = [];\n let addedToQueueCallbacks = new Map<string, () => void>;\n\n const next = async () => {\n while (true) {\n if (waitUntil > performance.now()) {\n await wait(Math.max(1, waitUntil - performance.now() + 1));\n } else if (queue.length === 0) {\n const uuid = generateUuid();\n await new Promise<void>(resolve => {\n addedToQueueCallbacks.set(uuid, resolve);\n });\n addedToQueueCallbacks.delete(uuid);\n } else {\n break;\n }\n }\n const nextFuncs = options.batchCalls ? queue.splice(0, queue.length) : [queue.shift()!];\n\n const start = performance.now();\n const value = await Result.fromPromise(func());\n const end = performance.now();\n\n waitUntil = Math.max(\n waitUntil,\n start + (options.throttleMs ?? 0),\n end + (options.gapMs ?? 0),\n );\n\n for (const nextFunc of nextFuncs) {\n if (value.status === \"ok\") {\n nextFunc[0](value.data);\n } else {\n nextFunc[1](value.error);\n }\n }\n };\n\n runAsynchronously(async () => {\n while (true) {\n await next();\n }\n });\n\n return () => {\n return new Promise<T>((resolve, reject) => {\n waitUntil = Math.max(\n waitUntil,\n performance.now() + (options.debounceMs ?? 0),\n );\n queue.push([resolve, reject]);\n addedToQueueCallbacks.forEach(cb => cb());\n });\n };\n}\n\nexport function throttled<T, A extends any[]>(func: (...args: A) => Promise<T>, delayMs: number): (...args: A) => Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let nextAvailable: Promise<T> | null = null;\n return async (...args) => {\n while (nextAvailable !== null) {\n await nextAvailable;\n }\n nextAvailable = new Promise<T>(resolve => {\n timeout = setTimeout(() => {\n nextAvailable = null;\n resolve(func(...args));\n }, delayMs);\n });\n return await nextAvailable;\n };\n}\n"],"mappings":"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","names":["waitUntil","timeout"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/promises.tsx"],"sourcesContent":["import { KnownError } from \"..\";\nimport { StackAssertionError, captureError, concatStacktraces, errorToNiceString } from \"./errors\";\nimport { DependenciesMap } from \"./maps\";\nimport { Result } from \"./results\";\nimport { generateUuid } from \"./uuids\";\n\nexport type ReactPromise<T> = Promise<T> & (\n | { status: \"rejected\", reason: unknown }\n | { status: \"fulfilled\", value: T }\n | { status: \"pending\" }\n);\n\ntype Resolve<T> = (value: T) => void;\ntype Reject = (reason: unknown) => void;\nexport function createPromise<T>(callback: (resolve: Resolve<T>, reject: Reject) => void): ReactPromise<T> {\n let status = \"pending\" as \"fulfilled\" | \"rejected\" | \"pending\";\n let valueOrReason: T | unknown | undefined = undefined;\n let resolve: Resolve<T> | null = null;\n let reject: Reject | null = null;\n const promise = new Promise<T>((res, rej) => {\n resolve = (value) => {\n if (status !== \"pending\") return;\n status = \"fulfilled\";\n valueOrReason = value;\n res(value);\n };\n reject = (reason) => {\n if (status !== \"pending\") return;\n status = \"rejected\";\n valueOrReason = reason;\n rej(reason);\n };\n });\n\n callback(resolve!, reject!);\n return Object.assign(promise, {\n status: status,\n ...status === \"fulfilled\" ? { value: valueOrReason as T } : {},\n ...status === \"rejected\" ? { reason: valueOrReason } : {},\n } as any);\n}\nundefined?.test(\"createPromise\", async ({ expect }) => {\n // Test resolved promise\n const resolvedPromise = createPromise<number>((resolve) => {\n resolve(42);\n });\n expect(resolvedPromise.status).toBe(\"fulfilled\");\n expect((resolvedPromise as any).value).toBe(42);\n expect(await resolvedPromise).toBe(42);\n\n // Test rejected promise\n const error = new Error(\"Test error\");\n const rejectedPromise = createPromise<number>((_, reject) => {\n reject(error);\n });\n expect(rejectedPromise.status).toBe(\"rejected\");\n expect((rejectedPromise as any).reason).toBe(error);\n await expect(rejectedPromise).rejects.toBe(error);\n\n // Test pending promise\n const pendingPromise = createPromise<number>(() => {\n // Do nothing, leave it pending\n });\n expect(pendingPromise.status).toBe(\"pending\");\n expect((pendingPromise as any).value).toBeUndefined();\n expect((pendingPromise as any).reason).toBeUndefined();\n\n // Test that resolving after already resolved does nothing\n let resolveCount = 0;\n const multiResolvePromise = createPromise<number>((resolve) => {\n resolve(1);\n resolveCount++;\n resolve(2);\n resolveCount++;\n });\n expect(resolveCount).toBe(2); // Both resolve calls executed\n expect(multiResolvePromise.status).toBe(\"fulfilled\");\n expect((multiResolvePromise as any).value).toBe(1); // Only first resolve took effect\n expect(await multiResolvePromise).toBe(1);\n});\n\nlet resolvedCache: DependenciesMap<[unknown], ReactPromise<unknown>> | null = null;\n/**\n * Like Promise.resolve(...), but also adds the status and value properties for use with React's `use` hook, and caches\n * the value so that invoking `resolved` twice returns the same promise.\n */\nexport function resolved<T>(value: T): ReactPromise<T> {\n resolvedCache ??= new DependenciesMap<[unknown], ReactPromise<unknown>>();\n if (resolvedCache.has([value])) {\n return resolvedCache.get([value]) as ReactPromise<T>;\n }\n\n const res = Object.assign(Promise.resolve(value), {\n status: \"fulfilled\",\n value,\n } as const);\n resolvedCache.set([value], res);\n return res;\n}\nundefined?.test(\"resolved\", async ({ expect }) => {\n // Test with primitive value\n const promise1 = resolved(42);\n expect(promise1.status).toBe(\"fulfilled\");\n // Need to use type assertion since value is only available when status is \"fulfilled\"\n expect((promise1 as { value: number }).value).toBe(42);\n expect(await promise1).toBe(42);\n\n // Test with object value\n const obj = { test: true };\n const promise2 = resolved(obj);\n expect(promise2.status).toBe(\"fulfilled\");\n expect((promise2 as { value: typeof obj }).value).toBe(obj);\n expect(await promise2).toBe(obj);\n\n // Test caching (same reference for same value)\n const promise3 = resolved(42);\n expect(promise3).toBe(promise1); // Same reference due to caching\n\n // Test with different value (different reference)\n const promise4 = resolved(43);\n expect(promise4).not.toBe(promise1);\n});\n\nlet rejectedCache: DependenciesMap<[unknown], ReactPromise<unknown>> | null = null;\n/**\n * Like Promise.reject(...), but also adds the status and value properties for use with React's `use` hook, and caches\n * the value so that invoking `rejected` twice returns the same promise.\n */\nexport function rejected<T>(reason: unknown): ReactPromise<T> {\n rejectedCache ??= new DependenciesMap<[unknown], ReactPromise<unknown>>();\n if (rejectedCache.has([reason])) {\n return rejectedCache.get([reason]) as ReactPromise<T>;\n }\n\n const promise = Promise.reject(reason);\n ignoreUnhandledRejection(promise);\n const res = Object.assign(promise, {\n status: \"rejected\",\n reason: reason,\n } as const);\n rejectedCache.set([reason], res);\n return res;\n}\nundefined?.test(\"rejected\", ({ expect }) => {\n // Test with error object\n const error = new Error(\"Test error\");\n const promise1 = rejected<number>(error);\n expect(promise1.status).toBe(\"rejected\");\n // Need to use type assertion since reason is only available when status is \"rejected\"\n expect((promise1 as { reason: Error }).reason).toBe(error);\n\n // Test with string reason\n const promise2 = rejected<string>(\"error message\");\n expect(promise2.status).toBe(\"rejected\");\n expect((promise2 as { reason: string }).reason).toBe(\"error message\");\n\n // Test caching (same reference for same reason)\n const promise3 = rejected<number>(error);\n expect(promise3).toBe(promise1); // Same reference due to caching\n\n // Test with different reason (different reference)\n const differentError = new Error(\"Different error\");\n const promise4 = rejected<number>(differentError);\n expect(promise4).not.toBe(promise1);\n\n // Note: We're not using await expect(promise).rejects to avoid unhandled rejections\n});\n\n// We'll skip the rejection test for pending() since it's causing unhandled rejections\n// The function is already well tested through other tests like rejected() and createPromise()\n\n\nconst neverResolvePromise = pending(new Promise<never>(() => {}));\nexport function neverResolve(): ReactPromise<never> {\n return neverResolvePromise;\n}\nundefined?.test(\"neverResolve\", ({ expect }) => {\n const promise = neverResolve();\n expect(promise.status).toBe(\"pending\");\n expect((promise as any).value).toBeUndefined();\n expect((promise as any).reason).toBeUndefined();\n\n // Test that multiple calls return the same promise\n const promise2 = neverResolve();\n expect(promise2).toBe(promise);\n});\n\nexport function pending<T>(promise: Promise<T>, options: { disableErrorWrapping?: boolean } = {}): ReactPromise<T> {\n const res = promise.then(\n value => {\n res.status = \"fulfilled\";\n (res as any).value = value;\n return value;\n },\n actualReason => {\n res.status = \"rejected\";\n (res as any).reason = actualReason;\n throw actualReason;\n },\n ) as ReactPromise<T>;\n res.status = \"pending\";\n return res;\n}\nundefined?.test(\"pending\", async ({ expect }) => {\n // Test with a promise that resolves\n const resolvePromise = Promise.resolve(42);\n const pendingPromise = pending(resolvePromise);\n\n // Initially it should be pending\n expect(pendingPromise.status).toBe(\"pending\");\n\n // After resolution, it should be fulfilled\n await resolvePromise;\n // Need to wait a tick for the then handler to execute\n await new Promise(resolve => setTimeout(resolve, 0));\n expect(pendingPromise.status).toBe(\"fulfilled\");\n expect((pendingPromise as { value: number }).value).toBe(42);\n\n // For the rejection test, we'll use a separate test to avoid unhandled rejections\n});\n\n/**\n * Should be used to wrap Promises that are not immediately awaited, so they don't throw an unhandled promise rejection\n * error.\n *\n * Vercel kills serverless functions on unhandled promise rejection errors, so this is important.\n */\nexport function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): void {\n promise.catch(() => {});\n}\nundefined?.test(\"ignoreUnhandledRejection\", async ({ expect }) => {\n // Test with a promise that resolves\n const resolvePromise = Promise.resolve(42);\n ignoreUnhandledRejection(resolvePromise);\n expect(await resolvePromise).toBe(42); // Should still resolve to the same value\n\n // Test with a promise that rejects\n // The promise should still reject, but the rejection is caught internally\n // so it doesn't cause an unhandled rejection error\n const error = new Error(\"Test error\");\n const rejectPromise = Promise.reject(error);\n ignoreUnhandledRejection(rejectPromise);\n await expect(rejectPromise).rejects.toBe(error);\n});\n\n/**\n * See concatStacktraces for more information.\n */\nexport function concatStacktracesIfRejected<T>(promise: Promise<T>): void {\n const currentError = new Error();\n promise.catch(error => {\n if (error instanceof Error) {\n concatStacktraces(error, currentError);\n } else {\n // we can only concatenate errors, so we'll just ignore the non-error\n }\n });\n}\n\nexport async function wait(ms: number) {\n if (!Number.isFinite(ms) || ms < 0) {\n throw new StackAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);\n }\n if (ms >= 2**31) {\n throw new StackAssertionError(\"The maximum timeout for wait() is 2147483647ms (2**31 - 1). (found: ${ms}ms)\");\n }\n return await new Promise<void>(resolve => setTimeout(resolve, ms));\n}\nundefined?.test(\"wait\", async ({ expect }) => {\n // Test with valid input\n const start = Date.now();\n await wait(10);\n const elapsed = Date.now() - start;\n expect(elapsed).toBeGreaterThanOrEqual(5); // Allow some flexibility in timing\n\n // Test with zero\n await expect(wait(0)).resolves.toBeUndefined();\n\n // Test with negative number\n await expect(wait(-10)).rejects.toThrow(\"wait() requires a non-negative integer\");\n\n // Test with non-finite number\n await expect(wait(NaN)).rejects.toThrow(\"wait() requires a non-negative integer\");\n await expect(wait(Infinity)).rejects.toThrow(\"wait() requires a non-negative integer\");\n\n // Test with too large number\n await expect(wait(2**31)).rejects.toThrow(\"The maximum timeout for wait()\");\n});\n\nexport async function waitUntil(date: Date) {\n return await wait(date.getTime() - Date.now());\n}\nundefined?.test(\"waitUntil\", async ({ expect }) => {\n // Test with future date\n const futureDate = new Date(Date.now() + 10);\n const start = Date.now();\n await waitUntil(futureDate);\n const elapsed = Date.now() - start;\n expect(elapsed).toBeGreaterThanOrEqual(5); // Allow some flexibility in timing\n\n // Test with past date - this will throw because wait() requires non-negative time\n // We need to verify it throws the correct error\n try {\n await waitUntil(new Date(Date.now() - 1000));\n expect.fail(\"Should have thrown an error\");\n } catch (error) {\n expect(error).toBeInstanceOf(StackAssertionError);\n expect((error as Error).message).toContain(\"wait() requires a non-negative integer\");\n }\n});\n\nexport function runAsynchronouslyWithAlert(...args: Parameters<typeof runAsynchronously>) {\n return runAsynchronously(\n args[0],\n {\n ...args[1],\n onError: error => {\n if (KnownError.isKnownError(error) && typeof process !== \"undefined\" && (process.env.NODE_ENV as any)?.includes(\"production\")) {\n alert(error.message);\n } else {\n alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === \"development\" ? `check the browser console for the full error.` : \"report this to the developer.\"}\\n\\n${error}`);\n }\n args[1]?.onError?.(error);\n },\n },\n ...args.slice(2) as [],\n );\n}\nundefined?.test(\"runAsynchronouslyWithAlert\", ({ expect }) => {\n // Simple test to verify the function calls runAsynchronously\n // We can't easily test the alert functionality without mocking\n const testFn = () => Promise.resolve(\"test\");\n const testOptions = { noErrorLogging: true };\n\n // Just verify it doesn't throw\n expect(() => runAsynchronouslyWithAlert(testFn, testOptions)).not.toThrow();\n\n // We can't easily test the error handling without mocking, so we'll\n // just verify the function exists and can be called\n expect(typeof runAsynchronouslyWithAlert).toBe(\"function\");\n});\n\nexport function runAsynchronously(\n promiseOrFunc: void | Promise<unknown> | (() => void | Promise<unknown>) | undefined,\n options: {\n noErrorLogging?: boolean,\n onError?: (error: Error) => void,\n } = {},\n): void {\n if (typeof promiseOrFunc === \"function\") {\n promiseOrFunc = promiseOrFunc();\n }\n if (promiseOrFunc) {\n concatStacktracesIfRejected(promiseOrFunc);\n promiseOrFunc.catch(error => {\n options.onError?.(error);\n const newError = new StackAssertionError(\n \"Uncaught error in asynchronous function: \" + errorToNiceString(error),\n { cause: error },\n );\n if (!options.noErrorLogging) {\n captureError(\"runAsynchronously\", newError);\n }\n });\n }\n}\nundefined?.test(\"runAsynchronously\", ({ expect }) => {\n // Simple test to verify the function exists and can be called\n const testFn = () => Promise.resolve(\"test\");\n\n // Just verify it doesn't throw\n expect(() => runAsynchronously(testFn)).not.toThrow();\n expect(() => runAsynchronously(Promise.resolve(\"test\"))).not.toThrow();\n expect(() => runAsynchronously(undefined)).not.toThrow();\n\n // We can't easily test the error handling without mocking, so we'll\n // just verify the function exists and can be called with options\n expect(() => runAsynchronously(testFn, { noErrorLogging: true })).not.toThrow();\n expect(() => runAsynchronously(testFn, { onError: () => {} })).not.toThrow();\n});\n\n\nclass TimeoutError extends Error {\n constructor(public readonly ms: number) {\n super(`Timeout after ${ms}ms`);\n this.name = \"TimeoutError\";\n }\n}\n\nexport async function timeout<T>(promise: Promise<T>, ms: number): Promise<Result<T, TimeoutError>> {\n return await Promise.race([\n promise.then(value => Result.ok(value)),\n wait(ms).then(() => Result.error(new TimeoutError(ms))),\n ]);\n}\nundefined?.test(\"timeout\", async ({ expect }) => {\n // Test with a promise that resolves quickly\n const fastPromise = Promise.resolve(42);\n const fastResult = await timeout(fastPromise, 100);\n expect(fastResult.status).toBe(\"ok\");\n if (fastResult.status === \"ok\") {\n expect(fastResult.data).toBe(42);\n }\n\n // Test with a promise that takes longer than the timeout\n const slowPromise = new Promise(resolve => setTimeout(() => resolve(\"too late\"), 50));\n const slowResult = await timeout(slowPromise, 10);\n expect(slowResult.status).toBe(\"error\");\n if (slowResult.status === \"error\") {\n expect(slowResult.error).toBeInstanceOf(TimeoutError);\n expect((slowResult.error as TimeoutError).ms).toBe(10);\n }\n});\n\nexport async function timeoutThrow<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Result.orThrow(await timeout(promise, ms));\n}\nundefined?.test(\"timeoutThrow\", async ({ expect }) => {\n // Test with a promise that resolves quickly\n const fastPromise = Promise.resolve(42);\n const fastResult = await timeoutThrow(fastPromise, 100);\n expect(fastResult).toBe(42);\n\n // Test with a promise that takes longer than the timeout\n const slowPromise = new Promise(resolve => setTimeout(() => resolve(\"too late\"), 50));\n await expect(timeoutThrow(slowPromise, 10)).rejects.toThrow(\"Timeout after 10ms\");\n await expect(timeoutThrow(slowPromise, 10)).rejects.toBeInstanceOf(TimeoutError);\n});\n\n\nexport type RateLimitOptions = {\n /**\n * The number of requests to process in parallel. Currently only 1 is supported.\n */\n concurrency: 1,\n\n /**\n * If true, multiple requests waiting at the same time will be reduced to just one. Default is false.\n */\n batchCalls?: boolean,\n\n /**\n * Waits for throttleMs since the start of last request before starting the next request. Default is 0.\n */\n throttleMs?: number,\n\n /**\n * Waits for gapMs since the end of last request before starting the next request. Default is 0.\n */\n gapMs?: number,\n\n /**\n * Waits until there have been no new requests for debounceMs before starting a new request. Default is 0.\n */\n debounceMs?: number,\n};\n\nexport function rateLimited<T>(\n func: () => Promise<T>,\n options: RateLimitOptions,\n): () => Promise<T> {\n let waitUntil = performance.now();\n let queue: [(t: T) => void, (e: unknown) => void][] = [];\n let addedToQueueCallbacks = new Map<string, () => void>;\n\n const next = async () => {\n while (true) {\n if (waitUntil > performance.now()) {\n await wait(Math.max(1, waitUntil - performance.now() + 1));\n } else if (queue.length === 0) {\n const uuid = generateUuid();\n await new Promise<void>(resolve => {\n addedToQueueCallbacks.set(uuid, resolve);\n });\n addedToQueueCallbacks.delete(uuid);\n } else {\n break;\n }\n }\n const nextFuncs = options.batchCalls ? queue.splice(0, queue.length) : [queue.shift()!];\n\n const start = performance.now();\n const value = await Result.fromPromise(func());\n const end = performance.now();\n\n waitUntil = Math.max(\n waitUntil,\n start + (options.throttleMs ?? 0),\n end + (options.gapMs ?? 0),\n );\n\n for (const nextFunc of nextFuncs) {\n if (value.status === \"ok\") {\n nextFunc[0](value.data);\n } else {\n nextFunc[1](value.error);\n }\n }\n };\n\n runAsynchronously(async () => {\n while (true) {\n await next();\n }\n });\n\n return () => {\n return new Promise<T>((resolve, reject) => {\n waitUntil = Math.max(\n waitUntil,\n performance.now() + (options.debounceMs ?? 0),\n );\n queue.push([resolve, reject]);\n addedToQueueCallbacks.forEach(cb => cb());\n });\n };\n}\n\nexport function throttled<T, A extends any[]>(func: (...args: A) => Promise<T>, delayMs: number): (...args: A) => Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let nextAvailable: Promise<T> | null = null;\n return async (...args) => {\n while (nextAvailable !== null) {\n await nextAvailable;\n }\n nextAvailable = new Promise<T>(resolve => {\n timeout = setTimeout(() => {\n nextAvailable = null;\n resolve(func(...args));\n }, delayMs);\n });\n return await nextAvailable;\n };\n}\n"],"mappings":"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","names":["waitUntil","timeout"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// src/utils/telemetry.tsx
|
|
2
|
+
import { trace } from "@opentelemetry/api";
|
|
3
|
+
import { getEnvVariable } from "./env.js";
|
|
4
|
+
import { StackAssertionError } from "./errors.js";
|
|
5
|
+
var tracer = trace.getTracer("stack-tracer");
|
|
6
|
+
function withTraceSpan(optionsOrDescription, fn) {
|
|
7
|
+
return async (...args) => {
|
|
8
|
+
return await traceSpan(optionsOrDescription, (span) => fn(...args));
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
async function traceSpan(optionsOrDescription, fn) {
|
|
12
|
+
let options = typeof optionsOrDescription === "string" ? { description: optionsOrDescription } : optionsOrDescription;
|
|
13
|
+
return await tracer.startActiveSpan(`STACK: ${options.description}`, async (span) => {
|
|
14
|
+
if (options.attributes) {
|
|
15
|
+
for (const [key, value] of Object.entries(options.attributes)) {
|
|
16
|
+
span.setAttribute(key, value);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
return await fn(span);
|
|
21
|
+
} finally {
|
|
22
|
+
span.end();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function log(message, attributes) {
|
|
27
|
+
const span = trace.getActiveSpan();
|
|
28
|
+
if (span) {
|
|
29
|
+
span.addEvent(message, attributes);
|
|
30
|
+
} else if (getEnvVariable("STACK_SEED_MODE", "false") !== "true") {
|
|
31
|
+
throw new StackAssertionError("No active span found");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
log,
|
|
36
|
+
traceSpan,
|
|
37
|
+
withTraceSpan
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/telemetry.tsx"],"sourcesContent":["import { Attributes, AttributeValue, Span, trace } from \"@opentelemetry/api\";\nimport { getEnvVariable } from \"./env\";\nimport { StackAssertionError } from \"./errors\";\n\nconst tracer = trace.getTracer('stack-tracer');\n\nexport function withTraceSpan<P extends any[], T>(optionsOrDescription: string | { description: string, attributes?: Record<string, AttributeValue> }, fn: (...args: P) => Promise<T>): (...args: P) => Promise<T> {\n return async (...args: P) => {\n return await traceSpan(optionsOrDescription, (span) => fn(...args));\n };\n}\n\nexport async function traceSpan<T>(optionsOrDescription: string | { description: string, attributes?: Record<string, AttributeValue> }, fn: (span: Span) => Promise<T>): Promise<T> {\n let options = typeof optionsOrDescription === 'string' ? { description: optionsOrDescription } : optionsOrDescription;\n return await tracer.startActiveSpan(`STACK: ${options.description}`, async (span) => {\n if (options.attributes) {\n for (const [key, value] of Object.entries(options.attributes)) {\n span.setAttribute(key, value);\n }\n }\n try {\n return await fn(span);\n } finally {\n span.end();\n }\n });\n}\n\nexport function log(message: string, attributes: Attributes) {\n const span = trace.getActiveSpan();\n if (span) {\n span.addEvent(message, attributes);\n // Telemetry is not initialized while seeding, so we don't want to throw an error\n } else if (getEnvVariable('STACK_SEED_MODE', 'false') !== 'true') {\n throw new StackAssertionError('No active span found');\n }\n}\n"],"mappings":";AAAA,SAA2C,aAAa;AACxD,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AAEpC,IAAM,SAAS,MAAM,UAAU,cAAc;AAEtC,SAAS,cAAkC,sBAAqG,IAA4D;AACjN,SAAO,UAAU,SAAY;AAC3B,WAAO,MAAM,UAAU,sBAAsB,CAAC,SAAS,GAAG,GAAG,IAAI,CAAC;AAAA,EACpE;AACF;AAEA,eAAsB,UAAa,sBAAqG,IAA4C;AAClL,MAAI,UAAU,OAAO,yBAAyB,WAAW,EAAE,aAAa,qBAAqB,IAAI;AACjG,SAAO,MAAM,OAAO,gBAAgB,UAAU,QAAQ,WAAW,IAAI,OAAO,SAAS;AACnF,QAAI,QAAQ,YAAY;AACtB,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,UAAU,GAAG;AAC7D,aAAK,aAAa,KAAK,KAAK;AAAA,MAC9B;AAAA,IACF;AACA,QAAI;AACF,aAAO,MAAM,GAAG,IAAI;AAAA,IACtB,UAAE;AACA,WAAK,IAAI;AAAA,IACX;AAAA,EACF,CAAC;AACH;AAEO,SAAS,IAAI,SAAiB,YAAwB;AAC3D,QAAM,OAAO,MAAM,cAAc;AACjC,MAAI,MAAM;AACR,SAAK,SAAS,SAAS,UAAU;AAAA,EAEnC,WAAW,eAAe,mBAAmB,OAAO,MAAM,QAAQ;AAChE,UAAM,IAAI,oBAAoB,sBAAsB;AAAA,EACtD;AACF;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare const previewTemplateSource: string;
|
|
2
2
|
declare const emptyEmailTheme: string;
|
|
3
|
-
declare const LightEmailTheme = "import { Html, Head, Tailwind, Body, Container } from '@react-email/components';\n\nexport function EmailTheme({ children }:
|
|
3
|
+
declare const LightEmailTheme = "import { Html, Head, Tailwind, Body, Container, Link } from '@react-email/components';\nimport { ThemeProps } from \"@stackframe/emails\"\n\nexport function EmailTheme({ children, unsubscribeLink }: ThemeProps) {\n return (\n <Html>\n <Head />\n <Tailwind>\n <Body className=\"bg-[#fafbfb] font-sans text-base\">\n <Container className=\"bg-white p-[45px] rounded-lg\">\n {children}\n </Container>\n {unsubscribeLink && (\n <div className=\"p-4\">\n <Link href={unsubscribeLink}>Click here{\" \"}</Link>\n to unsubscribe from these emails\n </div>\n )}\n </Body>\n </Tailwind>\n </Html>\n );\n}\n\nEmailTheme.PreviewProps = {\n unsubscribeLink: \"https://example.com\"\n} satisfies Partial<ThemeProps>\n";
|
|
4
4
|
declare const DEFAULT_EMAIL_THEME_ID = "1df07ae6-abf3-4a40-83a5-a1a2cbe336ac";
|
|
5
5
|
declare const DEFAULT_EMAIL_THEMES: {
|
|
6
6
|
"1df07ae6-abf3-4a40-83a5-a1a2cbe336ac": {
|
package/dist/helpers/emails.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare const previewTemplateSource: string;
|
|
2
2
|
declare const emptyEmailTheme: string;
|
|
3
|
-
declare const LightEmailTheme = "import { Html, Head, Tailwind, Body, Container } from '@react-email/components';\n\nexport function EmailTheme({ children }:
|
|
3
|
+
declare const LightEmailTheme = "import { Html, Head, Tailwind, Body, Container, Link } from '@react-email/components';\nimport { ThemeProps } from \"@stackframe/emails\"\n\nexport function EmailTheme({ children, unsubscribeLink }: ThemeProps) {\n return (\n <Html>\n <Head />\n <Tailwind>\n <Body className=\"bg-[#fafbfb] font-sans text-base\">\n <Container className=\"bg-white p-[45px] rounded-lg\">\n {children}\n </Container>\n {unsubscribeLink && (\n <div className=\"p-4\">\n <Link href={unsubscribeLink}>Click here{\" \"}</Link>\n to unsubscribe from these emails\n </div>\n )}\n </Body>\n </Tailwind>\n </Html>\n );\n}\n\nEmailTheme.PreviewProps = {\n unsubscribeLink: \"https://example.com\"\n} satisfies Partial<ThemeProps>\n";
|
|
4
4
|
declare const DEFAULT_EMAIL_THEME_ID = "1df07ae6-abf3-4a40-83a5-a1a2cbe336ac";
|
|
5
5
|
declare const DEFAULT_EMAIL_THEMES: {
|
|
6
6
|
"1df07ae6-abf3-4a40-83a5-a1a2cbe336ac": {
|
package/dist/helpers/emails.js
CHANGED
|
@@ -31,7 +31,7 @@ __export(emails_exports, {
|
|
|
31
31
|
module.exports = __toCommonJS(emails_exports);
|
|
32
32
|
var import_strings = require("../utils/strings.js");
|
|
33
33
|
var previewTemplateSource = import_strings.deindent`
|
|
34
|
-
import { Heading, Section, Button, Link, Column } from "@react-email/components";
|
|
34
|
+
import { Heading, Section, Row, Button, Link, Column } from "@react-email/components";
|
|
35
35
|
export const variablesSchema = v => v;
|
|
36
36
|
export function EmailTemplate() {
|
|
37
37
|
return <>
|
|
@@ -70,9 +70,10 @@ var emptyEmailTheme = import_strings.deindent`
|
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
`;
|
|
73
|
-
var LightEmailTheme = `import { Html, Head, Tailwind, Body, Container } from '@react-email/components';
|
|
73
|
+
var LightEmailTheme = `import { Html, Head, Tailwind, Body, Container, Link } from '@react-email/components';
|
|
74
|
+
import { ThemeProps } from "@stackframe/emails"
|
|
74
75
|
|
|
75
|
-
export function EmailTheme({ children }:
|
|
76
|
+
export function EmailTheme({ children, unsubscribeLink }: ThemeProps) {
|
|
76
77
|
return (
|
|
77
78
|
<Html>
|
|
78
79
|
<Head />
|
|
@@ -81,14 +82,26 @@ export function EmailTheme({ children }: { children: React.ReactNode }) {
|
|
|
81
82
|
<Container className="bg-white p-[45px] rounded-lg">
|
|
82
83
|
{children}
|
|
83
84
|
</Container>
|
|
85
|
+
{unsubscribeLink && (
|
|
86
|
+
<div className="p-4">
|
|
87
|
+
<Link href={unsubscribeLink}>Click here{" "}</Link>
|
|
88
|
+
to unsubscribe from these emails
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
84
91
|
</Body>
|
|
85
92
|
</Tailwind>
|
|
86
93
|
</Html>
|
|
87
94
|
);
|
|
88
|
-
}
|
|
89
|
-
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
EmailTheme.PreviewProps = {
|
|
98
|
+
unsubscribeLink: "https://example.com"
|
|
99
|
+
} satisfies Partial<ThemeProps>
|
|
100
|
+
`;
|
|
101
|
+
var DarkEmailTheme = `import { Html, Head, Tailwind, Body, Container, Link } from '@react-email/components';
|
|
102
|
+
import { ThemeProps } from "@stackframe/emails"
|
|
90
103
|
|
|
91
|
-
export function EmailTheme({ children }:
|
|
104
|
+
export function EmailTheme({ children, unsubscribeLink }: ThemeProps) {
|
|
92
105
|
return (
|
|
93
106
|
<Html>
|
|
94
107
|
<Head />
|
|
@@ -97,11 +110,22 @@ export function EmailTheme({ children }: { children: React.ReactNode }) {
|
|
|
97
110
|
<Container className="bg-black p-[45px] rounded-lg">
|
|
98
111
|
{children}
|
|
99
112
|
</Container>
|
|
113
|
+
{unsubscribeLink && (
|
|
114
|
+
<div className="p-4">
|
|
115
|
+
<Link href={unsubscribeLink}>Click here{" "}</Link>
|
|
116
|
+
to unsubscribe from these emails
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
100
119
|
</Body>
|
|
101
120
|
</Tailwind>
|
|
102
121
|
</Html>
|
|
103
122
|
);
|
|
104
|
-
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
EmailTheme.PreviewProps = {
|
|
126
|
+
unsubscribeLink: "https://example.com"
|
|
127
|
+
} satisfies Partial<ThemeProps>
|
|
128
|
+
`;
|
|
105
129
|
var DEFAULT_EMAIL_THEME_ID = "1df07ae6-abf3-4a40-83a5-a1a2cbe336ac";
|
|
106
130
|
var DEFAULT_EMAIL_THEMES = {
|
|
107
131
|
[DEFAULT_EMAIL_THEME_ID]: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helpers/emails.ts"],"sourcesContent":["import { deindent } from \"../utils/strings\";\n\nexport const previewTemplateSource = deindent`\n import { Heading, Section, Button, Link, Column } from \"@react-email/components\";\n export const variablesSchema = v => v;\n export function EmailTemplate() {\n return <>\n <Heading as=\"h2\" className=\"mb-4 text-2xl font-bold\">\n Header text\n </Heading>\n <Section className=\"mb-4\">\n Body text content with some additional information.\n </Section>\n <Row className=\"mb-4\">\n <Column>\n <Button href=\"https://example.com\">\n A button\n </Button>\n </Column>\n <Column>\n <Link href=\"https://example.com\">\n A link\n </Link>\n </Column>\n </Row>\n </>;\n }\n`;\n\nexport const emptyEmailTheme = deindent`\n import { Html, Tailwind, Body } from '@react-email/components';\n export function EmailTheme({ children }: { children: React.ReactNode }) {\n return (\n <Html>\n <Tailwind>\n <Body>\n {children}\n </Body>\n </Tailwind>\n </Html>\n );\n }\n`;\n\nexport const LightEmailTheme = `import { Html, Head, Tailwind, Body, Container } from '@react-email/components';\n\nexport function EmailTheme({ children }: { children: React.ReactNode }) {\n return (\n <Html>\n <Head />\n <Tailwind>\n <Body className=\"bg-[#fafbfb] font-sans text-base\">\n <Container className=\"bg-white p-[45px] rounded-lg\">\n {children}\n </Container>\n </Body>\n </Tailwind>\n </Html>\n );\n}`;\n\n\nconst DarkEmailTheme = `import { Html, Head, Tailwind, Body, Container } from '@react-email/components';\n\nexport function EmailTheme({ children }: { children: React.ReactNode }) {\n return (\n <Html>\n <Head />\n <Tailwind>\n <Body className=\"bg-[#323232] font-sans text-white\">\n <Container className=\"bg-black p-[45px] rounded-lg\">\n {children}\n </Container>\n </Body>\n </Tailwind>\n </Html>\n );\n}`;\n\n\nexport const DEFAULT_EMAIL_THEME_ID = \"1df07ae6-abf3-4a40-83a5-a1a2cbe336ac\";\n\nexport const DEFAULT_EMAIL_THEMES = {\n [DEFAULT_EMAIL_THEME_ID]: {\n displayName: 'Default Light',\n tsxSource: LightEmailTheme,\n },\n \"a0172b5d-cff0-463b-83bb-85124697373a\": {\n displayName: 'Default Dark',\n tsxSource: DarkEmailTheme,\n },\n};\n\nconst EMAIL_TEMPLATE_EMAIL_VERIFICATION_ID = \"e7d009ce-8d47-4528-b245-5bf119f2ffa3\";\nconst EMAIL_TEMPLATE_PASSWORD_RESET_ID = \"a70fb3a4-56c1-4e42-af25-49d25603abd0\";\nconst EMAIL_TEMPLATE_MAGIC_LINK_ID = \"822687fe-8d0a-4467-a0d1-416b6e639478\";\nconst EMAIL_TEMPLATE_TEAM_INVITATION_ID = \"e84de395-2076-4831-9c19-8e9a96a868e4\";\nconst EMAIL_TEMPLATE_SIGN_IN_INVITATION_ID = \"066dd73c-36da-4fd0-b6d6-ebf87683f8bc\";\n\nexport const DEFAULT_EMAIL_TEMPLATES = {\n [EMAIL_TEMPLATE_EMAIL_VERIFICATION_ID]: {\n \"displayName\": \"Email Verification\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\"\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\";\\nimport { Subject, NotificationCategory, Props } from \\\"@stackframe/emails\\\";\\n\\nexport const variablesSchema = type({\\n emailVerificationLink: \\\"string\\\"\\n})\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={`Verify your email at ${project.displayName}`} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-[0.15008px] leading-[1.5] m-0 py-8 w-full min-h-full\\\">\\n <Section className=\\\"bg-white\\\">\\n <h3 className=\\\"text-black font-sans font-bold text-[20px] text-center py-4 px-6 m-0\\\">\\n Verify your email at {project.displayName}\\n </h3>\\n <p className=\\\"text-[#474849] font-sans font-normal text-[14px] text-center pt-2 px-6 pb-4 m-0\\\">\\n Hi{user.displayName ? (\\\", \\\" + user.displayName) : ''}! Please click on the following button to verify your email.\\n </p>\\n <div className=\\\"text-center py-3 px-6\\\">\\n <Button\\n href={variables.emailVerificationLink}\\n target=\\\"_blank\\\"\\n className=\\\"text-black font-sans font-bold text-[14px] inline-block bg-[#f0f0f0] rounded-[4px] py-3 px-5 no-underline border-0\\\"\\n >\\n Verify my email\\n </Button>\\n </div>\\n <div className=\\\"py-4 px-6\\\">\\n <Hr />\\n </div>\\n <p className=\\\"text-[#474849] font-sans font-normal text-[12px] text-center pt-1 px-6 pb-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it. \\n </p>\\n </Section>\\n </div>\\n </>\\n )\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n emailVerificationLink: \\\"<email verification link>\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_PASSWORD_RESET_ID]: {\n \"displayName\": \"Password Reset\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\"\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\"\\nimport { Subject, NotificationCategory, Props} from \\\"@stackframe/emails\\\"\\n\\nexport const variablesSchema = type({\\n passwordResetLink: \\\"string\\\"\\n})\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={\\\"Reset your password at \\\" + project.displayName} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-tight leading-relaxed py-8 w-full min-h-full\\\">\\n <Section>\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-[20px] text-center py-4 px-6 m-0\\\">\\n Reset your password at {project.displayName}\\n </h3>\\n\\n <p className=\\\"text-[#474849] bg-transparent text-sm font-sans font-normal text-center pt-2 pb-4 px-6 m-0\\\">\\n Hi{user.displayName ? (\\\", \\\" + user.displayName) : \\\"\\\"}! Please click on the following button to start the password reset process.\\n </p>\\n\\n <div className=\\\"bg-transparent text-center px-6 py-3\\\">\\n <Button\\n href={variables.passwordResetLink}\\n className=\\\"text-black text-sm font-sans font-bold bg-[#f0f0f0] rounded-[4px] inline-block py-3 px-5 no-underline border-none\\\"\\n target=\\\"_blank\\\"\\n >\\n Reset my password\\n </Button>\\n </div>\\n\\n <div className=\\\"px-6 py-4\\\">\\n <Hr />\\n </div>\\n\\n <p className=\\\"text-[#474849] bg-transparent text-xs font-sans font-normal text-center pt-1 pb-6 px-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n )\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n passwordResetLink: \\\"<password reset link>\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_MAGIC_LINK_ID]: {\n \"displayName\": \"Magic Link/OTP\",\n \"tsxSource\": \"import { type } from 'arktype';\\nimport { Section, Hr } from '@react-email/components';\\nimport { Subject, NotificationCategory, Props } from '@stackframe/emails';\\n\\nexport const variablesSchema = type({\\n magicLink: 'string',\\n otp: 'string',\\n});\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={\\\"Sign in to \\\" + project.displayName + \\\": Your code is \\\" + variables.otp} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-[0.15008px] leading-6 m-0 py-8 w-full min-h-full\\\">\\n <Section className=\\\"mx-auto bg-white\\\">\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-xl text-center px-6 py-4 m-0\\\">\\n Sign in to {project.displayName}\\n </h3>\\n <p className=\\\"text-[#474849] bg-transparent text-sm font-sans font-normal text-center px-6 py-4 m-0\\\">\\n Hi{user.displayName ? \\\", \\\" + user.displayName : \\\"\\\"}! This is your one-time-password for signing in:\\n </p>\\n <p className=\\\"text-black bg-transparent text-2xl font-mono font-bold text-center px-6 py-4 m-0\\\">\\n {variables.otp}\\n </p>\\n <p className=\\\"text-black bg-transparent text-sm font-sans font-normal text-center px-6 py-4 m-0\\\">\\n Or you can click on{' '}\\n <a\\n key={20}\\n href={variables.magicLink}\\n target=\\\"_blank\\\"\\n rel=\\\"noopener noreferrer\\\"\\n className=\\\"text-blue-600 underline\\\"\\n >\\n this link\\n </a>{' '}\\n to sign in\\n </p>\\n <Hr className=\\\"px-6 py-4 bg-transparent\\\" />\\n <p className=\\\"text-[#474849] bg-transparent text-xs font-sans font-normal text-center px-6 pt-1 pb-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n );\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n magicLink: \\\"<magic link>\\\",\\n otp: \\\"3SLSWZ\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_TEAM_INVITATION_ID]: {\n \"displayName\": \"Team Invitation\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\";\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\";\\nimport { Subject, NotificationCategory, Props } from \\\"@stackframe/emails\\\";\\n\\n\\nexport const variablesSchema = type({\\n teamDisplayName: \\\"string\\\",\\n teamInvitationLink: \\\"string\\\"\\n});\\n\\nexport function EmailTemplate({ user, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={\\\"You have been invited to join \\\" + variables.teamDisplayName} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-[0.15008px] leading-[1.5] m-0 py-8 w-full min-h-full\\\">\\n <Section className=\\\"mx-auto max-w-lg bg-white\\\">\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-xl text-center px-6 pt-8 m-0\\\">\\n You are invited to {variables.teamDisplayName}\\n </h3>\\n <p className=\\\"text-[#474849] bg-transparent text-sm font-sans font-normal text-center px-6 pt-2 pb-4 m-0\\\">\\n Hi{user.displayName ? \\\", \\\" + user.displayName : \\\"\\\"}! Please click the button below to join the team {variables.teamDisplayName}\\n </p>\\n <div className=\\\"bg-transparent text-center px-6 py-3\\\">\\n <Button\\n href={variables.teamInvitationLink}\\n target=\\\"_blank\\\"\\n className=\\\"text-black text-sm font-sans font-bold bg-[#f0f0f0] rounded-md inline-block px-5 py-3 no-underline border-0\\\"\\n >\\n Join team\\n </Button>\\n </div>\\n <div className=\\\"px-6 py-4 bg-transparent\\\">\\n <Hr />\\n </div>\\n <p className=\\\"text-[#474849] bg-transparent text-xs font-sans font-normal text-center px-6 pb-6 pt-1 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n );\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n teamDisplayName: \\\"My Team\\\",\\n teamInvitationLink: \\\"<team invitation link>\\\"\\n} satisfies typeof variablesSchema.infer \",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_SIGN_IN_INVITATION_ID]: {\n \"displayName\": \"Sign In Invitation\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\"\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\";\\nimport { Subject, NotificationCategory, Props } from \\\"@stackframe/emails\\\";\\n\\nexport const variablesSchema = type({\\n signInInvitationLink: \\\"string\\\",\\n teamDisplayName: \\\"string\\\"\\n})\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject\\n value={\\\"You have been invited to sign in to \\\" + project.displayName}\\n />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n\\n <div className=\\\"bg-white text-gray-900 font-sans text-base font-normal leading-normal w-full min-h-full m-0 py-8\\\">\\n <Section>\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-xl text-center pt-8 px-6 m-0\\\">\\n You are invited to sign in to {variables.teamDisplayName}\\n </h3>\\n\\n <p className=\\\"text-gray-700 bg-transparent text-sm font-sans font-normal text-center pt-2 pb-4 px-6 m-0\\\">\\n Hi\\n {user.displayName ? \\\", \\\" + user.displayName : \\\"\\\"}! Please click on the following\\n link to sign in to your account\\n </p>\\n\\n <div className=\\\"bg-transparent text-center px-6 py-3\\\">\\n <Button\\n href={variables.signInInvitationLink}\\n className=\\\"text-black text-sm font-sans font-bold bg-gray-200 rounded-md inline-block py-3 px-5 no-underline border-none\\\"\\n target=\\\"_blank\\\"\\n >\\n Sign in\\n </Button>\\n </div>\\n\\n <div className=\\\"px-6 py-4 bg-transparent\\\">\\n <Hr />\\n </div>\\n\\n <p className=\\\"text-gray-700 bg-transparent text-xs font-sans font-normal text-center pt-1 pb-6 px-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n )\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n signInInvitationLink: \\\"<sign in invitation link>\\\",\\n teamDisplayName: \\\"My Team\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n }\n};\n\nexport const DEFAULT_TEMPLATE_IDS = {\n email_verification: EMAIL_TEMPLATE_EMAIL_VERIFICATION_ID,\n password_reset: EMAIL_TEMPLATE_PASSWORD_RESET_ID,\n magic_link: EMAIL_TEMPLATE_MAGIC_LINK_ID,\n team_invitation: EMAIL_TEMPLATE_TEAM_INVITATION_ID,\n sign_in_invitation: EMAIL_TEMPLATE_SIGN_IN_INVITATION_ID,\n} as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAyB;AAElB,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2B9B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAexB,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkB/B,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBhB,IAAM,yBAAyB;AAE/B,IAAM,uBAAuB;AAAA,EAClC,CAAC,sBAAsB,GAAG;AAAA,IACxB,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,wCAAwC;AAAA,IACtC,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AACF;AAEA,IAAM,uCAAuC;AAC7C,IAAM,mCAAmC;AACzC,IAAM,+BAA+B;AACrC,IAAM,oCAAoC;AAC1C,IAAM,uCAAuC;AAEtC,IAAM,0BAA0B;AAAA,EACrC,CAAC,oCAAoC,GAAG;AAAA,IACtC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,gCAAgC,GAAG;AAAA,IAClC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,4BAA4B,GAAG;AAAA,IAC9B,eAAe;AAAA,IACf,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,iCAAiC,GAAG;AAAA,IACnC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,oCAAoC,GAAG;AAAA,IACtC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,oBAAoB;AACtB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/emails.ts"],"sourcesContent":["import { deindent } from \"../utils/strings\";\n\nexport const previewTemplateSource = deindent`\n import { Heading, Section, Row, Button, Link, Column } from \"@react-email/components\";\n export const variablesSchema = v => v;\n export function EmailTemplate() {\n return <>\n <Heading as=\"h2\" className=\"mb-4 text-2xl font-bold\">\n Header text\n </Heading>\n <Section className=\"mb-4\">\n Body text content with some additional information.\n </Section>\n <Row className=\"mb-4\">\n <Column>\n <Button href=\"https://example.com\">\n A button\n </Button>\n </Column>\n <Column>\n <Link href=\"https://example.com\">\n A link\n </Link>\n </Column>\n </Row>\n </>;\n }\n`;\n\nexport const emptyEmailTheme = deindent`\n import { Html, Tailwind, Body } from '@react-email/components';\n export function EmailTheme({ children }: { children: React.ReactNode }) {\n return (\n <Html>\n <Tailwind>\n <Body>\n {children}\n </Body>\n </Tailwind>\n </Html>\n );\n }\n`;\n\nexport const LightEmailTheme = `import { Html, Head, Tailwind, Body, Container, Link } from '@react-email/components';\nimport { ThemeProps } from \"@stackframe/emails\"\n\nexport function EmailTheme({ children, unsubscribeLink }: ThemeProps) {\n return (\n <Html>\n <Head />\n <Tailwind>\n <Body className=\"bg-[#fafbfb] font-sans text-base\">\n <Container className=\"bg-white p-[45px] rounded-lg\">\n {children}\n </Container>\n {unsubscribeLink && (\n <div className=\"p-4\">\n <Link href={unsubscribeLink}>Click here{\" \"}</Link>\n to unsubscribe from these emails\n </div>\n )}\n </Body>\n </Tailwind>\n </Html>\n );\n}\n\nEmailTheme.PreviewProps = {\n unsubscribeLink: \"https://example.com\"\n} satisfies Partial<ThemeProps>\n`;\n\n\nconst DarkEmailTheme = `import { Html, Head, Tailwind, Body, Container, Link } from '@react-email/components';\nimport { ThemeProps } from \"@stackframe/emails\"\n\nexport function EmailTheme({ children, unsubscribeLink }: ThemeProps) {\n return (\n <Html>\n <Head />\n <Tailwind>\n <Body className=\"bg-[#323232] font-sans text-white\">\n <Container className=\"bg-black p-[45px] rounded-lg\">\n {children}\n </Container>\n {unsubscribeLink && (\n <div className=\"p-4\">\n <Link href={unsubscribeLink}>Click here{\" \"}</Link>\n to unsubscribe from these emails\n </div>\n )}\n </Body>\n </Tailwind>\n </Html>\n );\n}\n\nEmailTheme.PreviewProps = {\n unsubscribeLink: \"https://example.com\"\n} satisfies Partial<ThemeProps>\n`;\n\n\nexport const DEFAULT_EMAIL_THEME_ID = \"1df07ae6-abf3-4a40-83a5-a1a2cbe336ac\";\n\nexport const DEFAULT_EMAIL_THEMES = {\n [DEFAULT_EMAIL_THEME_ID]: {\n displayName: 'Default Light',\n tsxSource: LightEmailTheme,\n },\n \"a0172b5d-cff0-463b-83bb-85124697373a\": {\n displayName: 'Default Dark',\n tsxSource: DarkEmailTheme,\n },\n};\n\nconst EMAIL_TEMPLATE_EMAIL_VERIFICATION_ID = \"e7d009ce-8d47-4528-b245-5bf119f2ffa3\";\nconst EMAIL_TEMPLATE_PASSWORD_RESET_ID = \"a70fb3a4-56c1-4e42-af25-49d25603abd0\";\nconst EMAIL_TEMPLATE_MAGIC_LINK_ID = \"822687fe-8d0a-4467-a0d1-416b6e639478\";\nconst EMAIL_TEMPLATE_TEAM_INVITATION_ID = \"e84de395-2076-4831-9c19-8e9a96a868e4\";\nconst EMAIL_TEMPLATE_SIGN_IN_INVITATION_ID = \"066dd73c-36da-4fd0-b6d6-ebf87683f8bc\";\n\nexport const DEFAULT_EMAIL_TEMPLATES = {\n [EMAIL_TEMPLATE_EMAIL_VERIFICATION_ID]: {\n \"displayName\": \"Email Verification\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\"\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\";\\nimport { Subject, NotificationCategory, Props } from \\\"@stackframe/emails\\\";\\n\\nexport const variablesSchema = type({\\n emailVerificationLink: \\\"string\\\"\\n})\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={`Verify your email at ${project.displayName}`} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-[0.15008px] leading-[1.5] m-0 py-8 w-full min-h-full\\\">\\n <Section className=\\\"bg-white\\\">\\n <h3 className=\\\"text-black font-sans font-bold text-[20px] text-center py-4 px-6 m-0\\\">\\n Verify your email at {project.displayName}\\n </h3>\\n <p className=\\\"text-[#474849] font-sans font-normal text-[14px] text-center pt-2 px-6 pb-4 m-0\\\">\\n Hi{user.displayName ? (\\\", \\\" + user.displayName) : ''}! Please click on the following button to verify your email.\\n </p>\\n <div className=\\\"text-center py-3 px-6\\\">\\n <Button\\n href={variables.emailVerificationLink}\\n target=\\\"_blank\\\"\\n className=\\\"text-black font-sans font-bold text-[14px] inline-block bg-[#f0f0f0] rounded-[4px] py-3 px-5 no-underline border-0\\\"\\n >\\n Verify my email\\n </Button>\\n </div>\\n <div className=\\\"py-4 px-6\\\">\\n <Hr />\\n </div>\\n <p className=\\\"text-[#474849] font-sans font-normal text-[12px] text-center pt-1 px-6 pb-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it. \\n </p>\\n </Section>\\n </div>\\n </>\\n )\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n emailVerificationLink: \\\"<email verification link>\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_PASSWORD_RESET_ID]: {\n \"displayName\": \"Password Reset\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\"\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\"\\nimport { Subject, NotificationCategory, Props} from \\\"@stackframe/emails\\\"\\n\\nexport const variablesSchema = type({\\n passwordResetLink: \\\"string\\\"\\n})\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={\\\"Reset your password at \\\" + project.displayName} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-tight leading-relaxed py-8 w-full min-h-full\\\">\\n <Section>\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-[20px] text-center py-4 px-6 m-0\\\">\\n Reset your password at {project.displayName}\\n </h3>\\n\\n <p className=\\\"text-[#474849] bg-transparent text-sm font-sans font-normal text-center pt-2 pb-4 px-6 m-0\\\">\\n Hi{user.displayName ? (\\\", \\\" + user.displayName) : \\\"\\\"}! Please click on the following button to start the password reset process.\\n </p>\\n\\n <div className=\\\"bg-transparent text-center px-6 py-3\\\">\\n <Button\\n href={variables.passwordResetLink}\\n className=\\\"text-black text-sm font-sans font-bold bg-[#f0f0f0] rounded-[4px] inline-block py-3 px-5 no-underline border-none\\\"\\n target=\\\"_blank\\\"\\n >\\n Reset my password\\n </Button>\\n </div>\\n\\n <div className=\\\"px-6 py-4\\\">\\n <Hr />\\n </div>\\n\\n <p className=\\\"text-[#474849] bg-transparent text-xs font-sans font-normal text-center pt-1 pb-6 px-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n )\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n passwordResetLink: \\\"<password reset link>\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_MAGIC_LINK_ID]: {\n \"displayName\": \"Magic Link/OTP\",\n \"tsxSource\": \"import { type } from 'arktype';\\nimport { Section, Hr } from '@react-email/components';\\nimport { Subject, NotificationCategory, Props } from '@stackframe/emails';\\n\\nexport const variablesSchema = type({\\n magicLink: 'string',\\n otp: 'string',\\n});\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={\\\"Sign in to \\\" + project.displayName + \\\": Your code is \\\" + variables.otp} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-[0.15008px] leading-6 m-0 py-8 w-full min-h-full\\\">\\n <Section className=\\\"mx-auto bg-white\\\">\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-xl text-center px-6 py-4 m-0\\\">\\n Sign in to {project.displayName}\\n </h3>\\n <p className=\\\"text-[#474849] bg-transparent text-sm font-sans font-normal text-center px-6 py-4 m-0\\\">\\n Hi{user.displayName ? \\\", \\\" + user.displayName : \\\"\\\"}! This is your one-time-password for signing in:\\n </p>\\n <p className=\\\"text-black bg-transparent text-2xl font-mono font-bold text-center px-6 py-4 m-0\\\">\\n {variables.otp}\\n </p>\\n <p className=\\\"text-black bg-transparent text-sm font-sans font-normal text-center px-6 py-4 m-0\\\">\\n Or you can click on{' '}\\n <a\\n key={20}\\n href={variables.magicLink}\\n target=\\\"_blank\\\"\\n rel=\\\"noopener noreferrer\\\"\\n className=\\\"text-blue-600 underline\\\"\\n >\\n this link\\n </a>{' '}\\n to sign in\\n </p>\\n <Hr className=\\\"px-6 py-4 bg-transparent\\\" />\\n <p className=\\\"text-[#474849] bg-transparent text-xs font-sans font-normal text-center px-6 pt-1 pb-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n );\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n magicLink: \\\"<magic link>\\\",\\n otp: \\\"3SLSWZ\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_TEAM_INVITATION_ID]: {\n \"displayName\": \"Team Invitation\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\";\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\";\\nimport { Subject, NotificationCategory, Props } from \\\"@stackframe/emails\\\";\\n\\n\\nexport const variablesSchema = type({\\n teamDisplayName: \\\"string\\\",\\n teamInvitationLink: \\\"string\\\"\\n});\\n\\nexport function EmailTemplate({ user, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject value={\\\"You have been invited to join \\\" + variables.teamDisplayName} />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n <div className=\\\"bg-white text-[#242424] font-sans text-base font-normal tracking-[0.15008px] leading-[1.5] m-0 py-8 w-full min-h-full\\\">\\n <Section className=\\\"mx-auto max-w-lg bg-white\\\">\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-xl text-center px-6 pt-8 m-0\\\">\\n You are invited to {variables.teamDisplayName}\\n </h3>\\n <p className=\\\"text-[#474849] bg-transparent text-sm font-sans font-normal text-center px-6 pt-2 pb-4 m-0\\\">\\n Hi{user.displayName ? \\\", \\\" + user.displayName : \\\"\\\"}! Please click the button below to join the team {variables.teamDisplayName}\\n </p>\\n <div className=\\\"bg-transparent text-center px-6 py-3\\\">\\n <Button\\n href={variables.teamInvitationLink}\\n target=\\\"_blank\\\"\\n className=\\\"text-black text-sm font-sans font-bold bg-[#f0f0f0] rounded-md inline-block px-5 py-3 no-underline border-0\\\"\\n >\\n Join team\\n </Button>\\n </div>\\n <div className=\\\"px-6 py-4 bg-transparent\\\">\\n <Hr />\\n </div>\\n <p className=\\\"text-[#474849] bg-transparent text-xs font-sans font-normal text-center px-6 pb-6 pt-1 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n );\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n teamDisplayName: \\\"My Team\\\",\\n teamInvitationLink: \\\"<team invitation link>\\\"\\n} satisfies typeof variablesSchema.infer \",\n \"themeId\": undefined,\n },\n [EMAIL_TEMPLATE_SIGN_IN_INVITATION_ID]: {\n \"displayName\": \"Sign In Invitation\",\n \"tsxSource\": \"import { type } from \\\"arktype\\\"\\nimport { Button, Section, Hr } from \\\"@react-email/components\\\";\\nimport { Subject, NotificationCategory, Props } from \\\"@stackframe/emails\\\";\\n\\nexport const variablesSchema = type({\\n signInInvitationLink: \\\"string\\\",\\n teamDisplayName: \\\"string\\\"\\n})\\n\\nexport function EmailTemplate({ user, project, variables }: Props<typeof variablesSchema.infer>) {\\n return (\\n <>\\n <Subject\\n value={\\\"You have been invited to sign in to \\\" + project.displayName}\\n />\\n <NotificationCategory value=\\\"Transactional\\\" />\\n\\n <div className=\\\"bg-white text-gray-900 font-sans text-base font-normal leading-normal w-full min-h-full m-0 py-8\\\">\\n <Section>\\n <h3 className=\\\"text-black bg-transparent font-sans font-bold text-xl text-center pt-8 px-6 m-0\\\">\\n You are invited to sign in to {variables.teamDisplayName}\\n </h3>\\n\\n <p className=\\\"text-gray-700 bg-transparent text-sm font-sans font-normal text-center pt-2 pb-4 px-6 m-0\\\">\\n Hi\\n {user.displayName ? \\\", \\\" + user.displayName : \\\"\\\"}! Please click on the following\\n link to sign in to your account\\n </p>\\n\\n <div className=\\\"bg-transparent text-center px-6 py-3\\\">\\n <Button\\n href={variables.signInInvitationLink}\\n className=\\\"text-black text-sm font-sans font-bold bg-gray-200 rounded-md inline-block py-3 px-5 no-underline border-none\\\"\\n target=\\\"_blank\\\"\\n >\\n Sign in\\n </Button>\\n </div>\\n\\n <div className=\\\"px-6 py-4 bg-transparent\\\">\\n <Hr />\\n </div>\\n\\n <p className=\\\"text-gray-700 bg-transparent text-xs font-sans font-normal text-center pt-1 pb-6 px-6 m-0\\\">\\n If you were not expecting this email, you can safely ignore it.\\n </p>\\n </Section>\\n </div>\\n </>\\n )\\n}\\n\\nEmailTemplate.PreviewVariables = {\\n signInInvitationLink: \\\"<sign in invitation link>\\\",\\n teamDisplayName: \\\"My Team\\\"\\n} satisfies typeof variablesSchema.infer\",\n \"themeId\": undefined,\n }\n};\n\nexport const DEFAULT_TEMPLATE_IDS = {\n email_verification: EMAIL_TEMPLATE_EMAIL_VERIFICATION_ID,\n password_reset: EMAIL_TEMPLATE_PASSWORD_RESET_ID,\n magic_link: EMAIL_TEMPLATE_MAGIC_LINK_ID,\n team_invitation: EMAIL_TEMPLATE_TEAM_INVITATION_ID,\n sign_in_invitation: EMAIL_TEMPLATE_SIGN_IN_INVITATION_ID,\n} as const;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAyB;AAElB,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2B9B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAexB,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8B/B,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BhB,IAAM,yBAAyB;AAE/B,IAAM,uBAAuB;AAAA,EAClC,CAAC,sBAAsB,GAAG;AAAA,IACxB,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,wCAAwC;AAAA,IACtC,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AACF;AAEA,IAAM,uCAAuC;AAC7C,IAAM,mCAAmC;AACzC,IAAM,+BAA+B;AACrC,IAAM,oCAAoC;AAC1C,IAAM,uCAAuC;AAEtC,IAAM,0BAA0B;AAAA,EACrC,CAAC,oCAAoC,GAAG;AAAA,IACtC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,gCAAgC,GAAG;AAAA,IAClC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,4BAA4B,GAAG;AAAA,IAC9B,eAAe;AAAA,IACf,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,iCAAiC,GAAG;AAAA,IACnC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AAAA,EACA,CAAC,oCAAoC,GAAG;AAAA,IACtC,eAAe;AAAA,IACf,aAAa;AAAA,IACb,WAAW;AAAA,EACb;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,oBAAoB;AACtB;","names":[]}
|