@stackframe/stack-shared 2.8.27 → 2.8.30

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.
Files changed (86) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/config/schema.d.mts +391 -15
  3. package/dist/config/schema.d.ts +391 -15
  4. package/dist/config/schema.js +70 -2
  5. package/dist/config/schema.js.map +1 -1
  6. package/dist/esm/config/schema.js +70 -3
  7. package/dist/esm/config/schema.js.map +1 -1
  8. package/dist/esm/helpers/emails.js +31 -7
  9. package/dist/esm/helpers/emails.js.map +1 -1
  10. package/dist/esm/interface/admin-interface.js +65 -9
  11. package/dist/esm/interface/admin-interface.js.map +1 -1
  12. package/dist/esm/interface/crud/config.js +40 -0
  13. package/dist/esm/interface/crud/config.js.map +1 -0
  14. package/dist/esm/interface/crud/projects.js +4 -0
  15. package/dist/esm/interface/crud/projects.js.map +1 -1
  16. package/dist/esm/interface/server-interface.js +26 -0
  17. package/dist/esm/interface/server-interface.js.map +1 -1
  18. package/dist/esm/known-errors.js +73 -1
  19. package/dist/esm/known-errors.js.map +1 -1
  20. package/dist/esm/schema-fields.js +67 -4
  21. package/dist/esm/schema-fields.js.map +1 -1
  22. package/dist/esm/utils/errors.js.map +1 -1
  23. package/dist/esm/utils/esbuild.js +15 -11
  24. package/dist/esm/utils/esbuild.js.map +1 -1
  25. package/dist/esm/utils/featurebase.js +176 -0
  26. package/dist/esm/utils/featurebase.js.map +1 -0
  27. package/dist/esm/utils/html.js +6 -1
  28. package/dist/esm/utils/html.js.map +1 -1
  29. package/dist/esm/utils/promises.js +24 -13
  30. package/dist/esm/utils/promises.js.map +1 -1
  31. package/dist/esm/utils/telemetry.js +39 -0
  32. package/dist/esm/utils/telemetry.js.map +1 -0
  33. package/dist/helpers/emails.d.mts +1 -1
  34. package/dist/helpers/emails.d.ts +1 -1
  35. package/dist/helpers/emails.js +31 -7
  36. package/dist/helpers/emails.js.map +1 -1
  37. package/dist/index.d.mts +2 -1
  38. package/dist/index.d.ts +2 -1
  39. package/dist/interface/admin-interface.d.mts +15 -6
  40. package/dist/interface/admin-interface.d.ts +15 -6
  41. package/dist/interface/admin-interface.js +65 -9
  42. package/dist/interface/admin-interface.js.map +1 -1
  43. package/dist/interface/crud/config.d.mts +49 -0
  44. package/dist/interface/crud/config.d.ts +49 -0
  45. package/dist/interface/crud/config.js +79 -0
  46. package/dist/interface/crud/config.js.map +1 -0
  47. package/dist/interface/crud/project-api-keys.d.mts +4 -4
  48. package/dist/interface/crud/project-api-keys.d.ts +4 -4
  49. package/dist/interface/crud/projects.d.mts +35 -7
  50. package/dist/interface/crud/projects.d.ts +35 -7
  51. package/dist/interface/crud/projects.js +4 -0
  52. package/dist/interface/crud/projects.js.map +1 -1
  53. package/dist/interface/server-interface.d.mts +9 -0
  54. package/dist/interface/server-interface.d.ts +9 -0
  55. package/dist/interface/server-interface.js +26 -0
  56. package/dist/interface/server-interface.js.map +1 -1
  57. package/dist/known-errors.d.mts +15 -0
  58. package/dist/known-errors.d.ts +15 -0
  59. package/dist/known-errors.js +73 -1
  60. package/dist/known-errors.js.map +1 -1
  61. package/dist/schema-fields.d.mts +88 -2
  62. package/dist/schema-fields.d.ts +88 -2
  63. package/dist/schema-fields.js +71 -3
  64. package/dist/schema-fields.js.map +1 -1
  65. package/dist/utils/errors.d.mts +3 -1
  66. package/dist/utils/errors.d.ts +3 -1
  67. package/dist/utils/errors.js.map +1 -1
  68. package/dist/utils/esbuild.js +15 -11
  69. package/dist/utils/esbuild.js.map +1 -1
  70. package/dist/utils/featurebase.d.mts +28 -0
  71. package/dist/utils/featurebase.d.ts +28 -0
  72. package/dist/utils/featurebase.js +201 -0
  73. package/dist/utils/featurebase.js.map +1 -0
  74. package/dist/utils/html.d.mts +2 -1
  75. package/dist/utils/html.d.ts +2 -1
  76. package/dist/utils/html.js +8 -2
  77. package/dist/utils/html.js.map +1 -1
  78. package/dist/utils/promises.d.mts +5 -1
  79. package/dist/utils/promises.d.ts +5 -1
  80. package/dist/utils/promises.js +24 -12
  81. package/dist/utils/promises.js.map +1 -1
  82. package/dist/utils/telemetry.d.mts +13 -0
  83. package/dist/utils/telemetry.d.ts +13 -0
  84. package/dist/utils/telemetry.js +66 -0
  85. package/dist/utils/telemetry.js.map +1 -0
  86. 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":[]}
@@ -36,21 +36,25 @@ __export(esbuild_exports, {
36
36
  module.exports = __toCommonJS(esbuild_exports);
37
37
  var esbuild = __toESM(require("esbuild-wasm/lib/browser.js"));
38
38
  var import_path = require("path");
39
+ var import_env = require("./env.js");
39
40
  var import_errors = require("./errors.js");
40
41
  var import_results = require("./results.js");
41
- var import_env = require("./env.js");
42
+ var import_telemetry = require("./telemetry.js");
43
+ var esbuildWasmUrl = `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`;
42
44
  var esbuildInitializePromise = null;
43
45
  globalThis.self ??= globalThis;
44
- async function initializeEsbuild() {
46
+ function initializeEsbuild() {
45
47
  if (!esbuildInitializePromise) {
46
- esbuildInitializePromise = esbuild.initialize((0, import_env.isBrowserLike)() ? {
47
- wasmURL: `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`
48
- } : {
49
- wasmModule: await fetch(`https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`).then((wasm) => wasm.arrayBuffer()).then((wasm) => new WebAssembly.Module(wasm)),
50
- worker: false
51
- });
48
+ esbuildInitializePromise = (0, import_telemetry.withTraceSpan)("initializeEsbuild", async () => {
49
+ await esbuild.initialize((0, import_env.isBrowserLike)() ? {
50
+ wasmURL: esbuildWasmUrl
51
+ } : {
52
+ wasmModule: await fetch(esbuildWasmUrl).then((wasm) => wasm.arrayBuffer()).then((wasm) => new WebAssembly.Module(wasm)),
53
+ worker: false
54
+ });
55
+ })();
52
56
  }
53
- await esbuildInitializePromise;
57
+ return esbuildInitializePromise;
54
58
  }
55
59
  async function bundleJavaScript(sourceFiles, options = {}) {
56
60
  await initializeEsbuild();
@@ -67,7 +71,7 @@ async function bundleJavaScript(sourceFiles, options = {}) {
67
71
  ]);
68
72
  let result;
69
73
  try {
70
- result = await esbuild.build({
74
+ result = await (0, import_telemetry.traceSpan)("bundleJavaScript", async () => await esbuild.build({
71
75
  entryPoints: ["/entry.js"],
72
76
  bundle: true,
73
77
  write: false,
@@ -117,7 +121,7 @@ async function bundleJavaScript(sourceFiles, options = {}) {
117
121
  }
118
122
  }
119
123
  ]
120
- });
124
+ }));
121
125
  } catch (e) {
122
126
  if (e instanceof Error && e.message.startsWith("Build failed with ")) {
123
127
  return import_results.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 { isBrowserLike } from './env';\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 async function initializeEsbuild() {\n if (!esbuildInitializePromise) {\n esbuildInitializePromise = esbuild.initialize(isBrowserLike() ? {\n wasmURL: `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`,\n } : {\n wasmModule: (\n await fetch(`https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`)\n .then(wasm => wasm.arrayBuffer())\n .then(wasm => new WebAssembly.Module(wasm))\n ),\n worker: false,\n });\n }\n await 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 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
+ {"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"]}
@@ -0,0 +1,28 @@
1
+ type FeaturebaseUser = {
2
+ userId: string;
3
+ email: string;
4
+ name?: string;
5
+ profilePicture?: string;
6
+ };
7
+ type StackAuthUser = {
8
+ id: string;
9
+ primaryEmail: string | null;
10
+ displayName?: string | null;
11
+ profileImageUrl?: string | null;
12
+ };
13
+ /**
14
+ * Get or create a Featurebase user based on Stack Auth user data.
15
+ * This function ensures that:
16
+ * 1. We never change a user's email address on Featurebase
17
+ * 2. We use Stack Auth user ID as the primary identifier
18
+ * 3. We handle email conflicts by using fallback emails
19
+ * 4. We update profile information when needed
20
+ */
21
+ declare function getOrCreateFeaturebaseUser(stackAuthUser: StackAuthUser, options?: {
22
+ apiKey?: string;
23
+ }): Promise<{
24
+ userId: string;
25
+ email: string;
26
+ }>;
27
+
28
+ export { type FeaturebaseUser, type StackAuthUser, getOrCreateFeaturebaseUser };
@@ -0,0 +1,28 @@
1
+ type FeaturebaseUser = {
2
+ userId: string;
3
+ email: string;
4
+ name?: string;
5
+ profilePicture?: string;
6
+ };
7
+ type StackAuthUser = {
8
+ id: string;
9
+ primaryEmail: string | null;
10
+ displayName?: string | null;
11
+ profileImageUrl?: string | null;
12
+ };
13
+ /**
14
+ * Get or create a Featurebase user based on Stack Auth user data.
15
+ * This function ensures that:
16
+ * 1. We never change a user's email address on Featurebase
17
+ * 2. We use Stack Auth user ID as the primary identifier
18
+ * 3. We handle email conflicts by using fallback emails
19
+ * 4. We update profile information when needed
20
+ */
21
+ declare function getOrCreateFeaturebaseUser(stackAuthUser: StackAuthUser, options?: {
22
+ apiKey?: string;
23
+ }): Promise<{
24
+ userId: string;
25
+ email: string;
26
+ }>;
27
+
28
+ export { type FeaturebaseUser, type StackAuthUser, getOrCreateFeaturebaseUser };
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/utils/featurebase.tsx
21
+ var featurebase_exports = {};
22
+ __export(featurebase_exports, {
23
+ getOrCreateFeaturebaseUser: () => getOrCreateFeaturebaseUser
24
+ });
25
+ module.exports = __toCommonJS(featurebase_exports);
26
+ var import_env = require("./env.js");
27
+ var import_errors = require("./errors.js");
28
+ async function findFeaturebaseUserById(stackAuthUserId, apiKey) {
29
+ try {
30
+ const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?id=${stackAuthUserId}`, {
31
+ method: "GET",
32
+ headers: {
33
+ "X-API-Key": apiKey
34
+ }
35
+ });
36
+ if (response.status === 404) {
37
+ return null;
38
+ }
39
+ if (!response.ok) {
40
+ throw new import_errors.StackAssertionError(`Failed to find Featurebase user by ID: ${response.statusText}`);
41
+ }
42
+ const data = await response.json();
43
+ const user = data.user;
44
+ if (!user) {
45
+ throw new import_errors.StackAssertionError(`Featurebase API returned success but no user data for ID: ${stackAuthUserId}`, { data });
46
+ }
47
+ return {
48
+ userId: user.externalUserId || user.userId || stackAuthUserId,
49
+ email: user.email,
50
+ name: user.name,
51
+ profilePicture: user.profilePicture
52
+ };
53
+ } catch (error) {
54
+ if (error instanceof import_errors.StackAssertionError) {
55
+ throw error;
56
+ }
57
+ throw new import_errors.StackAssertionError("Failed to find Featurebase user by ID", { cause: error });
58
+ }
59
+ }
60
+ async function findFeaturebaseUserByEmail(email, apiKey) {
61
+ try {
62
+ const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?email=${encodeURIComponent(email)}`, {
63
+ method: "GET",
64
+ headers: {
65
+ "X-API-Key": apiKey
66
+ }
67
+ });
68
+ if (response.status === 404) {
69
+ return null;
70
+ }
71
+ if (!response.ok) {
72
+ throw new import_errors.StackAssertionError(`Failed to find Featurebase user by email: ${response.statusText}`);
73
+ }
74
+ const data = await response.json();
75
+ const user = data.user;
76
+ if (!user) {
77
+ throw new import_errors.StackAssertionError(`Featurebase API returned success but no user data for email: ${email}`, { data });
78
+ }
79
+ return {
80
+ userId: user.externalUserId || user.userId,
81
+ email: user.email,
82
+ name: user.name,
83
+ profilePicture: user.profilePicture
84
+ };
85
+ } catch (error) {
86
+ console.error("Error finding Featurebase user by email:", error);
87
+ return null;
88
+ }
89
+ }
90
+ async function createFeaturebaseUser(user, apiKey) {
91
+ try {
92
+ const response = await fetch("https://do.featurebase.app/v2/organization/identifyUser", {
93
+ method: "POST",
94
+ headers: {
95
+ "Content-Type": "application/json",
96
+ "X-API-Key": apiKey
97
+ },
98
+ body: JSON.stringify({
99
+ userId: user.userId,
100
+ email: user.email,
101
+ name: user.name,
102
+ profilePicture: user.profilePicture
103
+ })
104
+ });
105
+ if (!response.ok) {
106
+ const errorData = await response.json().catch(() => ({}));
107
+ throw new import_errors.StackAssertionError(`Failed to create Featurebase user: ${errorData.error || response.statusText}`, { errorData });
108
+ }
109
+ return user;
110
+ } catch (error) {
111
+ if (error instanceof import_errors.StackAssertionError) {
112
+ throw error;
113
+ }
114
+ throw new import_errors.StackAssertionError("Failed to create Featurebase user", { cause: error });
115
+ }
116
+ }
117
+ async function updateFeaturebaseUser(userId, updates, apiKey) {
118
+ try {
119
+ const response = await fetch(`https://do.featurebase.app/v2/users/${userId}`, {
120
+ method: "PATCH",
121
+ headers: {
122
+ "Content-Type": "application/json",
123
+ "X-API-Key": apiKey
124
+ },
125
+ body: JSON.stringify(updates)
126
+ });
127
+ if (!response.ok) {
128
+ const errorData = await response.json().catch(() => ({}));
129
+ throw new import_errors.StackAssertionError(`Failed to update Featurebase user: ${errorData.error || response.statusText}`, { errorData });
130
+ }
131
+ const data = await response.json();
132
+ return {
133
+ userId: data.userId || userId,
134
+ email: data.email,
135
+ name: data.name,
136
+ profilePicture: data.profilePicture
137
+ };
138
+ } catch (error) {
139
+ if (error instanceof import_errors.StackAssertionError) {
140
+ throw error;
141
+ }
142
+ throw new import_errors.StackAssertionError("Failed to update Featurebase user", { cause: error });
143
+ }
144
+ }
145
+ async function getOrCreateFeaturebaseUser(stackAuthUser, options) {
146
+ const apiKey = options?.apiKey || (0, import_env.getEnvVariable)("STACK_FEATUREBASE_API_KEY");
147
+ const fallbackEmail = `${stackAuthUser.id}@featurebase-user.stack-auth-app.com`;
148
+ const existingById = await findFeaturebaseUserById(stackAuthUser.id, apiKey);
149
+ if (existingById) {
150
+ let ensuredEmail = existingById.email;
151
+ if (!ensuredEmail) {
152
+ try {
153
+ await createFeaturebaseUser({
154
+ userId: existingById.userId,
155
+ email: fallbackEmail,
156
+ name: stackAuthUser.displayName || void 0,
157
+ profilePicture: stackAuthUser.profileImageUrl || void 0
158
+ }, apiKey);
159
+ ensuredEmail = fallbackEmail;
160
+ } catch (e) {
161
+ throw new import_errors.StackAssertionError(`Failed to set fallback email for existing Featurebase user ${existingById.userId}`, { cause: e });
162
+ }
163
+ }
164
+ try {
165
+ const updates = {};
166
+ if (stackAuthUser.displayName && stackAuthUser.displayName !== existingById.name) {
167
+ updates.name = stackAuthUser.displayName;
168
+ }
169
+ if (stackAuthUser.profileImageUrl && stackAuthUser.profileImageUrl !== existingById.profilePicture) {
170
+ updates.profilePicture = stackAuthUser.profileImageUrl;
171
+ }
172
+ if (Object.keys(updates).length > 0) {
173
+ await updateFeaturebaseUser(existingById.userId, updates, apiKey);
174
+ }
175
+ } catch (error) {
176
+ console.error("Failed to update existing Featurebase user profile:", error);
177
+ }
178
+ return {
179
+ userId: existingById.userId,
180
+ email: ensuredEmail
181
+ };
182
+ }
183
+ const candidateEmail = stackAuthUser.primaryEmail ?? fallbackEmail;
184
+ const existingByEmail = await findFeaturebaseUserByEmail(candidateEmail, apiKey);
185
+ const safeEmail = existingByEmail ? fallbackEmail : candidateEmail;
186
+ const created = await createFeaturebaseUser({
187
+ userId: stackAuthUser.id,
188
+ email: safeEmail,
189
+ name: stackAuthUser.displayName || stackAuthUser.primaryEmail?.split("@")[0] || "User",
190
+ profilePicture: stackAuthUser.profileImageUrl || void 0
191
+ }, apiKey);
192
+ return {
193
+ userId: created.userId,
194
+ email: created.email
195
+ };
196
+ }
197
+ // Annotate the CommonJS export names for ESM import in node:
198
+ 0 && (module.exports = {
199
+ getOrCreateFeaturebaseUser
200
+ });
201
+ //# sourceMappingURL=featurebase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/featurebase.tsx"],"sourcesContent":["import { getEnvVariable } from \"./env\";\nimport { StackAssertionError } from \"./errors\";\n\nexport type FeaturebaseUser = {\n userId: string,\n email: string,\n name?: string,\n profilePicture?: string,\n};\n\nexport type StackAuthUser = {\n id: string,\n primaryEmail: string | null,\n displayName?: string | null,\n profileImageUrl?: string | null,\n};\n\n/**\n * Find a Featurebase user by their Stack Auth user ID\n */\nasync function findFeaturebaseUserById(stackAuthUserId: string, apiKey: string): Promise<FeaturebaseUser | null> {\n try {\n const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?id=${stackAuthUserId}`, {\n method: 'GET',\n headers: {\n 'X-API-Key': apiKey,\n },\n });\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new StackAssertionError(`Failed to find Featurebase user by ID: ${response.statusText}`);\n }\n\n const data = await response.json();\n const user = data.user;\n\n if (!user) {\n throw new StackAssertionError(`Featurebase API returned success but no user data for ID: ${stackAuthUserId}`, { data });\n }\n\n return {\n userId: user.externalUserId || user.userId || stackAuthUserId,\n email: user.email,\n name: user.name,\n profilePicture: user.profilePicture,\n };\n } catch (error) {\n if (error instanceof StackAssertionError) {\n throw error;\n }\n throw new StackAssertionError(\"Failed to find Featurebase user by ID\", { cause: error });\n }\n}\n\n/**\n * Find a Featurebase user by their email address\n */\nasync function findFeaturebaseUserByEmail(email: string, apiKey: string): Promise<FeaturebaseUser | null> {\n try {\n const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?email=${encodeURIComponent(email)}`, {\n method: 'GET',\n headers: {\n 'X-API-Key': apiKey,\n },\n });\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new StackAssertionError(`Failed to find Featurebase user by email: ${response.statusText}`);\n }\n\n const data = await response.json();\n const user = data.user;\n\n if (!user) {\n throw new StackAssertionError(`Featurebase API returned success but no user data for email: ${email}`, { data });\n }\n\n return {\n userId: user.externalUserId || user.userId,\n email: user.email,\n name: user.name,\n profilePicture: user.profilePicture,\n };\n } catch (error) {\n console.error('Error finding Featurebase user by email:', error);\n return null;\n }\n}\n\n/**\n * Create a new Featurebase user using the identifyUser endpoint\n */\nasync function createFeaturebaseUser(user: FeaturebaseUser, apiKey: string): Promise<FeaturebaseUser> {\n try {\n const response = await fetch('https://do.featurebase.app/v2/organization/identifyUser', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify({\n userId: user.userId,\n email: user.email,\n name: user.name,\n profilePicture: user.profilePicture,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new StackAssertionError(`Failed to create Featurebase user: ${errorData.error || response.statusText}`, { errorData });\n }\n\n // The identifyUser endpoint just returns { \"success\": true }, so we return the input data\n return user;\n } catch (error) {\n if (error instanceof StackAssertionError) {\n throw error;\n }\n throw new StackAssertionError(\"Failed to create Featurebase user\", { cause: error });\n\n }\n}\n\n/**\n * Update an existing Featurebase user (excluding email)\n */\nasync function updateFeaturebaseUser(userId: string, updates: Partial<Omit<FeaturebaseUser, 'userId' | 'email'>>, apiKey: string): Promise<FeaturebaseUser> {\n try {\n const response = await fetch(`https://do.featurebase.app/v2/users/${userId}`, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify(updates),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new StackAssertionError(`Failed to update Featurebase user: ${errorData.error || response.statusText}`, { errorData });\n }\n\n const data = await response.json();\n return {\n userId: data.userId || userId,\n email: data.email,\n name: data.name,\n profilePicture: data.profilePicture,\n };\n } catch (error) {\n if (error instanceof StackAssertionError) {\n throw error;\n }\n throw new StackAssertionError(\"Failed to update Featurebase user\", { cause: error });\n }\n}\n\n/**\n * Get or create a Featurebase user based on Stack Auth user data.\n * This function ensures that:\n * 1. We never change a user's email address on Featurebase\n * 2. We use Stack Auth user ID as the primary identifier\n * 3. We handle email conflicts by using fallback emails\n * 4. We update profile information when needed\n */\nexport async function getOrCreateFeaturebaseUser(\n stackAuthUser: StackAuthUser,\n options?: { apiKey?: string }\n): Promise<{ userId: string, email: string }> {\n const apiKey = options?.apiKey || getEnvVariable(\"STACK_FEATUREBASE_API_KEY\");\n const fallbackEmail = `${stackAuthUser.id}@featurebase-user.stack-auth-app.com`;\n\n // First, try to find existing user by Stack Auth user ID\n const existingById = await findFeaturebaseUserById(stackAuthUser.id, apiKey);\n if (existingById) {\n // Ensure the user has an email on Featurebase.\n let ensuredEmail = existingById.email;\n if (!ensuredEmail) {\n try {\n await createFeaturebaseUser({\n userId: existingById.userId,\n email: fallbackEmail,\n name: stackAuthUser.displayName || undefined,\n profilePicture: stackAuthUser.profileImageUrl || undefined,\n }, apiKey);\n ensuredEmail = fallbackEmail;\n } catch (e) {\n // If setting fallback email failed, keep ensuredEmail as-is (undefined) and let callers handle\n throw new StackAssertionError(`Failed to set fallback email for existing Featurebase user ${existingById.userId}`, { cause: e });\n }\n }\n\n // Update profile information if needed (but not email)\n try {\n const updates: Partial<Omit<FeaturebaseUser, 'userId' | 'email'>> = {};\n\n if (stackAuthUser.displayName && stackAuthUser.displayName !== existingById.name) {\n updates.name = stackAuthUser.displayName;\n }\n\n if (stackAuthUser.profileImageUrl && stackAuthUser.profileImageUrl !== existingById.profilePicture) {\n updates.profilePicture = stackAuthUser.profileImageUrl;\n }\n\n if (Object.keys(updates).length > 0) {\n await updateFeaturebaseUser(existingById.userId, updates, apiKey);\n }\n } catch (error) {\n console.error('Failed to update existing Featurebase user profile:', error);\n // Continue with existing user data even if update fails\n }\n\n return {\n userId: existingById.userId,\n email: ensuredEmail,\n };\n }\n\n // No existing user found by ID, need to create one\n const candidateEmail = stackAuthUser.primaryEmail ?? fallbackEmail;\n\n // Check if someone already has this email on Featurebase\n const existingByEmail = await findFeaturebaseUserByEmail(candidateEmail, apiKey);\n const safeEmail = existingByEmail ? fallbackEmail : candidateEmail;\n\n // Create new user\n const created = await createFeaturebaseUser({\n userId: stackAuthUser.id,\n email: safeEmail,\n name: stackAuthUser.displayName || stackAuthUser.primaryEmail?.split('@')[0] || 'User',\n profilePicture: stackAuthUser.profileImageUrl || undefined,\n }, apiKey);\n\n return {\n userId: created.userId,\n email: created.email,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,5 @@
1
1
  declare function escapeHtml(unsafe: string): string;
2
2
  declare function html(strings: TemplateStringsArray, ...values: any[]): string;
3
+ declare function htmlToText(untrustedHtml: string): string;
3
4
 
4
- export { escapeHtml, html };
5
+ export { escapeHtml, html, htmlToText };
@@ -1,4 +1,5 @@
1
1
  declare function escapeHtml(unsafe: string): string;
2
2
  declare function html(strings: TemplateStringsArray, ...values: any[]): string;
3
+ declare function htmlToText(untrustedHtml: string): string;
3
4
 
4
- export { escapeHtml, html };
5
+ export { escapeHtml, html, htmlToText };
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var html_exports = {};
22
22
  __export(html_exports, {
23
23
  escapeHtml: () => escapeHtml,
24
- html: () => html
24
+ html: () => html,
25
+ htmlToText: () => htmlToText
25
26
  });
26
27
  module.exports = __toCommonJS(html_exports);
27
28
  var import_strings = require("./strings.js");
@@ -31,9 +32,14 @@ function escapeHtml(unsafe) {
31
32
  function html(strings, ...values) {
32
33
  return (0, import_strings.templateIdentity)(strings, ...values.map((v) => escapeHtml(`${v}`)));
33
34
  }
35
+ function htmlToText(untrustedHtml) {
36
+ const doc = new DOMParser().parseFromString(untrustedHtml, "text/html");
37
+ return doc.body.textContent ?? "";
38
+ }
34
39
  // Annotate the CommonJS export names for ESM import in node:
35
40
  0 && (module.exports = {
36
41
  escapeHtml,
37
- html
42
+ html,
43
+ htmlToText
38
44
  });
39
45
  //# sourceMappingURL=html.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/html.tsx"],"sourcesContent":["import { templateIdentity } from \"./strings\";\n\nexport function escapeHtml(unsafe: string): string {\n return `${unsafe}`\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\nundefined?.test(\"escapeHtml\", ({ expect }) => {\n // Test with empty string\n expect(escapeHtml(\"\")).toBe(\"\");\n\n // Test with string without special characters\n expect(escapeHtml(\"hello world\")).toBe(\"hello world\");\n\n // Test with special characters\n expect(escapeHtml(\"<div>\")).toBe(\"&lt;div&gt;\");\n expect(escapeHtml(\"a & b\")).toBe(\"a &amp; b\");\n expect(escapeHtml('a \"quoted\" string')).toBe(\"a &quot;quoted&quot; string\");\n expect(escapeHtml(\"it's a test\")).toBe(\"it&#039;s a test\");\n\n // Test with multiple special characters\n expect(escapeHtml(\"<a href=\\\"test\\\">It's a link</a>\")).toBe(\n \"&lt;a href=&quot;test&quot;&gt;It&#039;s a link&lt;/a&gt;\"\n );\n});\n\nexport function html(strings: TemplateStringsArray, ...values: any[]): string {\n return templateIdentity(strings, ...values.map(v => escapeHtml(`${v}`)));\n}\nundefined?.test(\"html\", ({ expect }) => {\n // Test with no interpolation\n expect(html`simple string`).toBe(\"simple string\");\n\n // Test with string interpolation\n expect(html`Hello, ${\"world\"}!`).toBe(\"Hello, world!\");\n\n // Test with number interpolation\n expect(html`Count: ${42}`).toBe(\"Count: 42\");\n\n // Test with HTML special characters in interpolated values\n expect(html`<div>${\"<script>\"}</div>`).toBe(\"<div>&lt;script&gt;</div>\");\n\n // Test with multiple interpolations\n expect(html`${1} + ${2} = ${\"<3\"}`).toBe(\"1 + 2 = &lt;3\");\n\n // Test with object interpolation\n const obj = { toString: () => \"<object>\" };\n expect(html`Object: ${obj}`).toBe(\"Object: &lt;object&gt;\");\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAiC;AAE1B,SAAS,WAAW,QAAwB;AACjD,SAAO,GAAG,MAAM,GACb,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAoBO,SAAS,KAAK,YAAkC,QAAuB;AAC5E,aAAO,iCAAiB,SAAS,GAAG,OAAO,IAAI,OAAK,WAAW,GAAG,CAAC,EAAE,CAAC,CAAC;AACzE;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/html.tsx"],"sourcesContent":["import { templateIdentity } from \"./strings\";\n\nexport function escapeHtml(unsafe: string): string {\n return `${unsafe}`\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\nundefined?.test(\"escapeHtml\", ({ expect }) => {\n // Test with empty string\n expect(escapeHtml(\"\")).toBe(\"\");\n\n // Test with string without special characters\n expect(escapeHtml(\"hello world\")).toBe(\"hello world\");\n\n // Test with special characters\n expect(escapeHtml(\"<div>\")).toBe(\"&lt;div&gt;\");\n expect(escapeHtml(\"a & b\")).toBe(\"a &amp; b\");\n expect(escapeHtml('a \"quoted\" string')).toBe(\"a &quot;quoted&quot; string\");\n expect(escapeHtml(\"it's a test\")).toBe(\"it&#039;s a test\");\n\n // Test with multiple special characters\n expect(escapeHtml(\"<a href=\\\"test\\\">It's a link</a>\")).toBe(\n \"&lt;a href=&quot;test&quot;&gt;It&#039;s a link&lt;/a&gt;\"\n );\n});\n\nexport function html(strings: TemplateStringsArray, ...values: any[]): string {\n return templateIdentity(strings, ...values.map(v => escapeHtml(`${v}`)));\n}\nundefined?.test(\"html\", ({ expect }) => {\n // Test with no interpolation\n expect(html`simple string`).toBe(\"simple string\");\n\n // Test with string interpolation\n expect(html`Hello, ${\"world\"}!`).toBe(\"Hello, world!\");\n\n // Test with number interpolation\n expect(html`Count: ${42}`).toBe(\"Count: 42\");\n\n // Test with HTML special characters in interpolated values\n expect(html`<div>${\"<script>\"}</div>`).toBe(\"<div>&lt;script&gt;</div>\");\n\n // Test with multiple interpolations\n expect(html`${1} + ${2} = ${\"<3\"}`).toBe(\"1 + 2 = &lt;3\");\n\n // Test with object interpolation\n const obj = { toString: () => \"<object>\" };\n expect(html`Object: ${obj}`).toBe(\"Object: &lt;object&gt;\");\n});\n\nexport function htmlToText(untrustedHtml: string): string {\n\n const doc = new DOMParser().parseFromString(untrustedHtml, 'text/html');\n\n return doc.body.textContent ?? '';\n\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAiC;AAE1B,SAAS,WAAW,QAAwB;AACjD,SAAO,GAAG,MAAM,GACb,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAoBO,SAAS,KAAK,YAAkC,QAAuB;AAC5E,aAAO,iCAAiB,SAAS,GAAG,OAAO,IAAI,OAAK,WAAW,GAAG,CAAC,EAAE,CAAC,CAAC;AACzE;AAsBO,SAAS,WAAW,eAA+B;AAExD,QAAM,MAAM,IAAI,UAAU,EAAE,gBAAgB,eAAe,WAAW;AAEtE,SAAO,IAAI,KAAK,eAAe;AAEjC;","names":[]}
@@ -33,6 +33,10 @@ declare function pending<T>(promise: Promise<T>, options?: {
33
33
  * Vercel kills serverless functions on unhandled promise rejection errors, so this is important.
34
34
  */
35
35
  declare function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): void;
36
+ /**
37
+ * See concatStacktraces for more information.
38
+ */
39
+ declare function concatStacktracesIfRejected<T>(promise: Promise<T>): void;
36
40
  declare function wait(ms: number): Promise<void>;
37
41
  declare function waitUntil(date: Date): Promise<void>;
38
42
  declare function runAsynchronouslyWithAlert(...args: Parameters<typeof runAsynchronously>): void;
@@ -71,4 +75,4 @@ type RateLimitOptions = {
71
75
  declare function rateLimited<T>(func: () => Promise<T>, options: RateLimitOptions): () => Promise<T>;
72
76
  declare function throttled<T, A extends any[]>(func: (...args: A) => Promise<T>, delayMs: number): (...args: A) => Promise<T>;
73
77
 
74
- export { type RateLimitOptions, type ReactPromise, createPromise, ignoreUnhandledRejection, neverResolve, pending, rateLimited, rejected, resolved, runAsynchronously, runAsynchronouslyWithAlert, throttled, timeout, timeoutThrow, wait, waitUntil };
78
+ export { type RateLimitOptions, type ReactPromise, concatStacktracesIfRejected, createPromise, ignoreUnhandledRejection, neverResolve, pending, rateLimited, rejected, resolved, runAsynchronously, runAsynchronouslyWithAlert, throttled, timeout, timeoutThrow, wait, waitUntil };
@@ -33,6 +33,10 @@ declare function pending<T>(promise: Promise<T>, options?: {
33
33
  * Vercel kills serverless functions on unhandled promise rejection errors, so this is important.
34
34
  */
35
35
  declare function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): void;
36
+ /**
37
+ * See concatStacktraces for more information.
38
+ */
39
+ declare function concatStacktracesIfRejected<T>(promise: Promise<T>): void;
36
40
  declare function wait(ms: number): Promise<void>;
37
41
  declare function waitUntil(date: Date): Promise<void>;
38
42
  declare function runAsynchronouslyWithAlert(...args: Parameters<typeof runAsynchronously>): void;
@@ -71,4 +75,4 @@ type RateLimitOptions = {
71
75
  declare function rateLimited<T>(func: () => Promise<T>, options: RateLimitOptions): () => Promise<T>;
72
76
  declare function throttled<T, A extends any[]>(func: (...args: A) => Promise<T>, delayMs: number): (...args: A) => Promise<T>;
73
77
 
74
- export { type RateLimitOptions, type ReactPromise, createPromise, ignoreUnhandledRejection, neverResolve, pending, rateLimited, rejected, resolved, runAsynchronously, runAsynchronouslyWithAlert, throttled, timeout, timeoutThrow, wait, waitUntil };
78
+ export { type RateLimitOptions, type ReactPromise, concatStacktracesIfRejected, createPromise, ignoreUnhandledRejection, neverResolve, pending, rateLimited, rejected, resolved, runAsynchronously, runAsynchronouslyWithAlert, throttled, timeout, timeoutThrow, wait, waitUntil };
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/utils/promises.tsx
21
21
  var promises_exports = {};
22
22
  __export(promises_exports, {
23
+ concatStacktracesIfRejected: () => concatStacktracesIfRejected,
23
24
  createPromise: () => createPromise,
24
25
  ignoreUnhandledRejection: () => ignoreUnhandledRejection,
25
26
  neverResolve: () => neverResolve,
@@ -120,6 +121,15 @@ function ignoreUnhandledRejection(promise) {
120
121
  promise.catch(() => {
121
122
  });
122
123
  }
124
+ function concatStacktracesIfRejected(promise) {
125
+ const currentError = new Error();
126
+ promise.catch((error) => {
127
+ if (error instanceof Error) {
128
+ (0, import_errors.concatStacktraces)(error, currentError);
129
+ } else {
130
+ }
131
+ });
132
+ }
123
133
  async function wait(ms) {
124
134
  if (!Number.isFinite(ms) || ms < 0) {
125
135
  throw new import_errors.StackAssertionError(`wait() requires a non-negative integer number of milliseconds to wait. (found: ${ms}ms)`);
@@ -155,18 +165,19 @@ function runAsynchronously(promiseOrFunc, options = {}) {
155
165
  if (typeof promiseOrFunc === "function") {
156
166
  promiseOrFunc = promiseOrFunc();
157
167
  }
158
- const duringError = new Error();
159
- promiseOrFunc?.catch((error) => {
160
- options.onError?.(error);
161
- const newError = new import_errors.StackAssertionError(
162
- "Uncaught error in asynchronous function: " + error.toString(),
163
- { cause: error }
164
- );
165
- (0, import_errors.concatStacktraces)(newError, duringError);
166
- if (!options.noErrorLogging) {
167
- (0, import_errors.captureError)("runAsynchronously", newError);
168
- }
169
- });
168
+ if (promiseOrFunc) {
169
+ concatStacktracesIfRejected(promiseOrFunc);
170
+ promiseOrFunc.catch((error) => {
171
+ options.onError?.(error);
172
+ const newError = new import_errors.StackAssertionError(
173
+ "Uncaught error in asynchronous function: " + (0, import_errors.errorToNiceString)(error),
174
+ { cause: error }
175
+ );
176
+ if (!options.noErrorLogging) {
177
+ (0, import_errors.captureError)("runAsynchronously", newError);
178
+ }
179
+ });
180
+ }
170
181
  }
171
182
  var TimeoutError = class extends Error {
172
183
  constructor(ms) {
@@ -253,6 +264,7 @@ function throttled(func, delayMs) {
253
264
  }
254
265
  // Annotate the CommonJS export names for ESM import in node:
255
266
  0 && (module.exports = {
267
+ concatStacktracesIfRejected,
256
268
  createPromise,
257
269
  ignoreUnhandledRejection,
258
270
  neverResolve,