diff --git a/packages/otel-resend/CHANGELOG.md b/packages/otel-resend/CHANGELOG.md
new file mode 100644
index 0000000..03dff5b
--- /dev/null
+++ b/packages/otel-resend/CHANGELOG.md
@@ -0,0 +1,5 @@
+# @kubiks/otel-resend
+
+## 1.0.0
+
+- Initial release.
diff --git a/packages/otel-resend/LICENSE b/packages/otel-resend/LICENSE
new file mode 100644
index 0000000..55f20b0
--- /dev/null
+++ b/packages/otel-resend/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Kubiks
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/otel-resend/README.md b/packages/otel-resend/README.md
new file mode 100644
index 0000000..44cd78b
--- /dev/null
+++ b/packages/otel-resend/README.md
@@ -0,0 +1,82 @@
+# @kubiks/otel-resend
+
+OpenTelemetry instrumentation for the [Resend](https://resend.com) Node.js SDK.
+Capture spans for every Resend API call, enrich them with operation metadata,
+and keep an eye on message delivery from your traces.
+
+## Installation
+
+```bash
+npm install @kubiks/otel-resend
+# or
+pnpm add @kubiks/otel-resend
+```
+
+**Peer Dependencies:** `@opentelemetry/api` >= 1.9.0, `resend` >= 3.0.0
+
+## Quick Start
+
+```ts
+import { Resend } from "resend";
+import { instrumentResend } from "@kubiks/otel-resend";
+
+const resend = instrumentResend(new Resend(process.env.RESEND_API_KEY!));
+
+await resend.emails.send({
+ from: "hello@example.com",
+ to: ["user@example.com"],
+ subject: "Welcome",
+ html: "
Hello world
",
+});
+```
+
+`instrumentResend` wraps the instance you already use—no configuration changes
+needed. Every SDK call creates a client span with useful attributes.
+
+## What Gets Traced
+
+- All top-level Resend client methods (e.g. `resend.ping`)
+- Nested resource methods such as `resend.emails.send`, `resend.emails.batch`,
+ `resend.domains.create`, `resend.apiKeys.create`, and custom resources
+- Both async and sync methods defined on resource instances or their prototypes
+
+## Span Attributes
+
+Each span includes:
+
+| Attribute | Description | Example |
+| --- | --- | --- |
+| `messaging.system` | Constant value `resend` | `resend` |
+| `messaging.operation` | Operation derived from the method name | `send`, `create`, `list` |
+| `resend.resource` | Top-level resource name | `emails`, `domains` |
+| `resend.target` | Fully-qualified target (resource + method) | `emails.send` |
+| `resend.recipient_count` | Total recipients detected in the request payload | `3` |
+| `resend.template_id` | Template referenced in the request (when present) | `tmpl_123` |
+| `resend.message_id` | Message ID returned by email operations | `email_123` |
+| `resend.message_count` | How many message IDs were returned | `2` |
+| `resend.resource_id` | Identifier returned by non-email resources | `domain_456` |
+
+Sensitive request payloads are never recorded—only counts and identifiers that
+Resend already exposes.
+
+## Configuration
+
+```ts
+instrumentResend(resend, {
+ tracerName: "my-service",
+ captureRequestMetadata: true,
+ captureResponseMetadata: true,
+ shouldInstrument: (path, method) => !(path[0] === "emails" && method === "list"),
+});
+```
+
+- `tracerName` / `tracer`: reuse an existing tracer if you have one.
+- `captureRequestMetadata`: toggle attributes derived from the request payload
+ (recipient counts, template IDs). Enabled by default.
+- `captureResponseMetadata`: toggle attributes derived from the response
+ (message IDs, resource IDs). Enabled by default.
+- `shouldInstrument`: skip specific methods programmatically.
+
+## License
+
+MIT
diff --git a/packages/otel-resend/package.json b/packages/otel-resend/package.json
new file mode 100644
index 0000000..7d4d95e
--- /dev/null
+++ b/packages/otel-resend/package.json
@@ -0,0 +1,53 @@
+{
+ "name": "@kubiks/otel-resend",
+ "version": "1.0.0",
+ "private": false,
+ "publishConfig": {
+ "access": "public"
+ },
+ "description": "OpenTelemetry instrumentation for the Resend Node.js SDK",
+ "author": "Kubiks",
+ "license": "MIT",
+ "repository": "kubiks-inc/otel",
+ "sideEffects": false,
+ "type": "module",
+ "exports": {
+ ".": {
+ "types": "./dist/types/index.d.ts",
+ "import": "./dist/index.js",
+ "default": "./dist/index.js"
+ }
+ },
+ "main": "./dist/index.js",
+ "types": "./dist/types/index.d.ts",
+ "files": [
+ "dist",
+ "LICENSE",
+ "README.md"
+ ],
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "scripts": {
+ "build": "pnpm clean && tsc",
+ "clean": "rimraf dist",
+ "prepublishOnly": "pnpm build",
+ "type-check": "tsc --noEmit",
+ "unit-test": "vitest --run",
+ "unit-test-watch": "vitest"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "@opentelemetry/api": "^1.9.0",
+ "@opentelemetry/sdk-trace-base": "^2.1.0",
+ "@types/node": "18.15.11",
+ "resend": "^3.0.0",
+ "rimraf": "3.0.2",
+ "typescript": "^5",
+ "vitest": "0.33.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.9.0 <2.0.0",
+ "resend": ">=3.0.0"
+ }
+}
diff --git a/packages/otel-resend/src/index.test.ts b/packages/otel-resend/src/index.test.ts
new file mode 100644
index 0000000..547ccb8
--- /dev/null
+++ b/packages/otel-resend/src/index.test.ts
@@ -0,0 +1,190 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import { SpanStatusCode, trace } from "@opentelemetry/api";
+import {
+ BasicTracerProvider,
+ InMemorySpanExporter,
+ SimpleSpanProcessor,
+} from "@opentelemetry/sdk-trace-base";
+import {
+ instrumentResend,
+ SEMATTRS_MESSAGING_OPERATION,
+ SEMATTRS_MESSAGING_SYSTEM,
+ SEMATTRS_RESEND_MESSAGE_COUNT,
+ SEMATTRS_RESEND_MESSAGE_ID,
+ SEMATTRS_RESEND_RECIPIENT_COUNT,
+ SEMATTRS_RESEND_RESOURCE,
+ SEMATTRS_RESEND_RESOURCE_ID,
+ SEMATTRS_RESEND_TARGET,
+ SEMATTRS_RESEND_TEMPLATE_ID,
+} from "./index";
+
+describe("instrumentResend", () => {
+ let provider: BasicTracerProvider;
+ let exporter: InMemorySpanExporter;
+
+ beforeEach(() => {
+ exporter = new InMemorySpanExporter();
+ provider = new BasicTracerProvider({
+ spanProcessors: [new SimpleSpanProcessor(exporter)],
+ });
+ trace.setGlobalTracerProvider(provider);
+ });
+
+ afterEach(async () => {
+ await provider.shutdown();
+ exporter.reset();
+ trace.disable();
+ });
+
+ const createMockResend = () => {
+ class EmailsResource {
+ async send(payload: Record) {
+ return { id: "email_123", payload };
+ }
+
+ async list() {
+ return { data: [{ id: "email_1" }, { id: "email_2" }] };
+ }
+
+ fail() {
+ throw new Error("boom");
+ }
+ }
+
+ class DomainsResource {
+ async create() {
+ return { id: "domain_123" };
+ }
+ }
+
+ return {
+ emails: new EmailsResource(),
+ domains: new DomainsResource(),
+ apiKeys: {
+ create: vi.fn(async () => ({ id: "key_abc" })),
+ },
+ ping: vi.fn(() => "pong"),
+ };
+ };
+
+ it("wraps methods and records spans", async () => {
+ const resend = createMockResend();
+ instrumentResend(resend);
+
+ const payload = {
+ to: ["user@example.com", { email: "second@example.com" }],
+ template_id: "tmpl_123",
+ };
+
+ const response = await resend.emails.send(payload);
+ expect(response.id).toBe("email_123");
+
+ const spans = exporter.getFinishedSpans();
+ expect(spans).toHaveLength(1);
+
+ const span = spans[0];
+ if (!span) {
+ throw new Error("Expected a span to be recorded");
+ }
+
+ expect(span.name).toBe("resend.emails.send");
+ expect(span.attributes[SEMATTRS_MESSAGING_SYSTEM]).toBe("resend");
+ expect(span.attributes[SEMATTRS_MESSAGING_OPERATION]).toBe("send");
+ expect(span.attributes[SEMATTRS_RESEND_RESOURCE]).toBe("emails");
+ expect(span.attributes[SEMATTRS_RESEND_TARGET]).toBe("emails.send");
+ expect(span.attributes[SEMATTRS_RESEND_MESSAGE_ID]).toBe("email_123");
+ expect(span.attributes[SEMATTRS_RESEND_MESSAGE_COUNT]).toBe(1);
+ expect(span.attributes[SEMATTRS_RESEND_RECIPIENT_COUNT]).toBe(2);
+ expect(span.attributes[SEMATTRS_RESEND_TEMPLATE_ID]).toBe("tmpl_123");
+ expect(span.status.code).toBe(SpanStatusCode.OK);
+ });
+
+ it("records spans for prototype methods", async () => {
+ const resend = createMockResend();
+ instrumentResend(resend);
+
+ await resend.domains.create();
+
+ const spans = exporter.getFinishedSpans();
+ expect(spans).toHaveLength(1);
+
+ const span = spans[0];
+ if (!span) {
+ throw new Error("Expected a span to be recorded");
+ }
+
+ expect(span.name).toBe("resend.domains.create");
+ expect(span.attributes[SEMATTRS_RESEND_RESOURCE]).toBe("domains");
+ expect(span.attributes[SEMATTRS_RESEND_MESSAGE_ID]).toBeUndefined();
+ expect(span.attributes[SEMATTRS_RESEND_RESOURCE_ID]).toBe("domain_123");
+ expect(span.status.code).toBe(SpanStatusCode.OK);
+ });
+
+ it("handles synchronous functions", () => {
+ const resend = createMockResend();
+ instrumentResend(resend);
+
+ const result = resend.ping();
+ expect(result).toBe("pong");
+
+ const spans = exporter.getFinishedSpans();
+ expect(spans).toHaveLength(1);
+
+ const span = spans[0];
+ if (!span) {
+ throw new Error("Expected a span to be recorded");
+ }
+
+ expect(span.name).toBe("resend.ping");
+ expect(span.status.code).toBe(SpanStatusCode.OK);
+ });
+
+ it("captures errors and marks span status", async () => {
+ const resend = createMockResend();
+ instrumentResend(resend);
+
+ await expect(async () => resend.emails.fail()).rejects.toThrowError("boom");
+
+ const spans = exporter.getFinishedSpans();
+ expect(spans).toHaveLength(1);
+
+ const span = spans[0];
+ if (!span) {
+ throw new Error("Expected a span to be recorded");
+ }
+
+ expect(span.status.code).toBe(SpanStatusCode.ERROR);
+ const hasException = span.events.some((event) => event.name === "exception");
+ expect(hasException).toBe(true);
+ });
+
+ it("is idempotent", async () => {
+ const resend = createMockResend();
+ const first = instrumentResend(resend);
+ const second = instrumentResend(first);
+
+ expect(first).toBe(second);
+ expect(first.emails.send).toBe(second.emails.send);
+
+ await second.emails.send({});
+
+ expect(exporter.getFinishedSpans()).toHaveLength(1);
+ });
+
+ it("respects shouldInstrument filter", async () => {
+ const resend = createMockResend();
+ instrumentResend(resend, {
+ shouldInstrument: (path, methodName) => {
+ if (path[0] === "emails" && methodName === "list") {
+ return false;
+ }
+ return true;
+ },
+ });
+
+ await resend.emails.list();
+
+ const spans = exporter.getFinishedSpans();
+ expect(spans).toHaveLength(0);
+ });
+});
diff --git a/packages/otel-resend/src/index.ts b/packages/otel-resend/src/index.ts
new file mode 100644
index 0000000..ace5492
--- /dev/null
+++ b/packages/otel-resend/src/index.ts
@@ -0,0 +1,465 @@
+import {
+ context,
+ SpanKind,
+ SpanStatusCode,
+ trace,
+ type Span,
+ type Tracer,
+} from "@opentelemetry/api";
+
+const DEFAULT_TRACER_NAME = "@kubiks/otel-resend";
+const INSTRUMENTED_FLAG = "__kubiksOtelResendInstrumented" as const;
+const INSTRUMENTED_METHOD_FLAG = Symbol("kubiksOtelResendInstrumentedMethod");
+
+export const SEMATTRS_MESSAGING_SYSTEM = "messaging.system" as const;
+export const SEMATTRS_MESSAGING_OPERATION = "messaging.operation" as const;
+export const SEMATTRS_RESEND_RESOURCE = "resend.resource" as const;
+export const SEMATTRS_RESEND_TARGET = "resend.target" as const;
+export const SEMATTRS_RESEND_MESSAGE_ID = "resend.message_id" as const;
+export const SEMATTRS_RESEND_MESSAGE_COUNT = "resend.message_count" as const;
+export const SEMATTRS_RESEND_TEMPLATE_ID = "resend.template_id" as const;
+export const SEMATTRS_RESEND_SEGMENT_ID = "resend.segment_id" as const;
+export const SEMATTRS_RESEND_AUDIENCE_ID = "resend.audience_id" as const;
+export const SEMATTRS_RESEND_RECIPIENT_COUNT = "resend.recipient_count" as const;
+export const SEMATTRS_RESEND_RESOURCE_ID = "resend.resource_id" as const;
+
+export interface InstrumentResendConfig {
+ tracerName?: string;
+ tracer?: Tracer;
+ captureRequestMetadata?: boolean;
+ captureResponseMetadata?: boolean;
+ shouldInstrument?(
+ path: readonly string[],
+ methodName: string,
+ original: AnyFunction,
+ ): boolean;
+}
+
+type AnyFunction = (...args: unknown[]) => unknown;
+type ResendLike = Record;
+
+interface InstrumentedResendLike extends ResendLike {
+ [INSTRUMENTED_FLAG]?: true;
+}
+
+interface NormalizedConfig {
+ tracer: Tracer;
+ tracerName: string;
+ captureRequestMetadata: boolean;
+ captureResponseMetadata: boolean;
+ shouldInstrument(
+ path: readonly string[],
+ methodName: string,
+ original: AnyFunction,
+ ): boolean;
+}
+
+const instrumentedObjects = new WeakSet();
+const defaultShouldInstrument: NormalizedConfig["shouldInstrument"] = () => true;
+
+function toSnakeCase(input: string): string {
+ return input
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
+ .replace(/[\s./-]+/g, "_")
+ .toLowerCase();
+}
+
+function buildSpanName(path: readonly string[], methodName: string): string {
+ const parts = [...path, methodName].filter(Boolean);
+ return parts.length ? `resend.${parts.join(".")}` : "resend.call";
+}
+
+function buildBaseAttributes(
+ path: readonly string[],
+ methodName: string,
+): Record {
+ const attributes: Record = {
+ [SEMATTRS_MESSAGING_SYSTEM]: "resend",
+ [SEMATTRS_MESSAGING_OPERATION]: toSnakeCase(methodName),
+ [SEMATTRS_RESEND_TARGET]: [...path, methodName].join("."),
+ };
+
+ if (path[0]) {
+ attributes[SEMATTRS_RESEND_RESOURCE] = path[0];
+ }
+
+ return attributes;
+}
+
+function countRecipients(value: unknown): number {
+ if (!value) {
+ return 0;
+ }
+ if (typeof value === "string") {
+ return value.trim() ? 1 : 0;
+ }
+ if (Array.isArray(value)) {
+ return value.reduce((count, item) => count + countRecipients(item), 0);
+ }
+ if (typeof value === "object") {
+ // Array-like or iterable structures
+ if (typeof (value as { length?: number }).length === "number") {
+ return (value as { length: number }).length;
+ }
+ if (Symbol.iterator in (value as object)) {
+ let count = 0;
+ for (const item of value as Iterable) {
+ count += countRecipients(item);
+ }
+ return count;
+ }
+ if (
+ typeof (value as { email?: unknown }).email === "string" ||
+ typeof (value as { address?: unknown }).address === "string"
+ ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+function annotateRequest(
+ span: Span,
+ path: readonly string[],
+ args: unknown[],
+ capture: boolean,
+): void {
+ if (!capture || !args.length) {
+ return;
+ }
+
+ const payload = args[0];
+ if (!payload || typeof payload !== "object") {
+ return;
+ }
+
+ const data = payload as Record;
+
+ const recipientCount =
+ countRecipients(data.to) + countRecipients(data.cc) + countRecipients(data.bcc);
+ if (recipientCount > 0) {
+ span.setAttribute(SEMATTRS_RESEND_RECIPIENT_COUNT, recipientCount);
+ }
+
+ const templateId =
+ (typeof data.template_id === "string" && data.template_id) ||
+ (typeof data.templateId === "string" && data.templateId) ||
+ (typeof data.template === "string" && data.template);
+ if (templateId) {
+ span.setAttribute(SEMATTRS_RESEND_TEMPLATE_ID, templateId);
+ }
+
+ const segmentId =
+ (typeof data.segment_id === "string" && data.segment_id) ||
+ (typeof data.segmentId === "string" && data.segmentId);
+ if (segmentId) {
+ span.setAttribute(SEMATTRS_RESEND_SEGMENT_ID, segmentId);
+ }
+
+ const audienceId =
+ (typeof data.audience_id === "string" && data.audience_id) ||
+ (typeof data.audienceId === "string" && data.audienceId);
+ if (audienceId) {
+ span.setAttribute(SEMATTRS_RESEND_AUDIENCE_ID, audienceId);
+ }
+}
+
+function collectIdentifiers(value: unknown, depth = 0): string[] {
+ if (!value || depth > 3) {
+ return [];
+ }
+
+ if (typeof value === "string") {
+ return value ? [value] : [];
+ }
+
+ if (Array.isArray(value)) {
+ return value.flatMap((item) => collectIdentifiers(item, depth + 1));
+ }
+
+ if (typeof value === "object") {
+ const record = value as Record;
+ const ids: string[] = [];
+
+ const directId =
+ (typeof record.id === "string" && record.id) ||
+ (typeof record.messageId === "string" && record.messageId) ||
+ (typeof record.message_id === "string" && record.message_id);
+ if (directId) {
+ ids.push(directId);
+ }
+
+ const nestedKeys = ["data", "items", "messages", "results", "entries"];
+ for (const key of nestedKeys) {
+ if (key in record) {
+ ids.push(...collectIdentifiers(record[key], depth + 1));
+ }
+ }
+
+ return ids;
+ }
+
+ return [];
+}
+
+function annotateResponse(
+ span: Span,
+ resource: string | undefined,
+ result: unknown,
+ capture: boolean,
+): void {
+ if (!capture) {
+ return;
+ }
+
+ const identifiers = collectIdentifiers(result);
+ if (!identifiers.length) {
+ return;
+ }
+
+ const uniqueIds = Array.from(new Set(identifiers));
+ span.setAttribute(SEMATTRS_RESEND_MESSAGE_COUNT, uniqueIds.length);
+
+ if (resource === "emails") {
+ if (uniqueIds.length === 1) {
+ span.setAttribute(SEMATTRS_RESEND_MESSAGE_ID, uniqueIds[0]!);
+ }
+ } else if (uniqueIds.length === 1) {
+ span.setAttribute(SEMATTRS_RESEND_RESOURCE_ID, uniqueIds[0]!);
+ }
+}
+
+function finalizeSpan(span: Span, error?: unknown): void {
+ if (error) {
+ if (error instanceof Error) {
+ span.recordException(error);
+ } else {
+ span.recordException(new Error(String(error)));
+ }
+ span.setStatus({ code: SpanStatusCode.ERROR });
+ } else {
+ span.setStatus({ code: SpanStatusCode.OK });
+ }
+ span.end();
+}
+
+function wrapMethod(
+ original: AnyFunction,
+ path: readonly string[],
+ methodName: string,
+ tracer: Tracer,
+ config: NormalizedConfig,
+): AnyFunction {
+ const spanName = buildSpanName(path, methodName);
+ const baseAttributes = buildBaseAttributes(path, methodName);
+ const resource = path[0];
+
+ const instrumented = function instrumentedResendMethod(
+ this: unknown,
+ ...args: unknown[]
+ ) {
+ const span = tracer.startSpan(spanName, {
+ kind: SpanKind.CLIENT,
+ attributes: baseAttributes,
+ });
+
+ annotateRequest(span, path, args, config.captureRequestMetadata);
+
+ const activeContext = trace.setSpan(context.active(), span);
+
+ const invokeOriginal = () => original.apply(this, args);
+
+ try {
+ const result = context.with(activeContext, invokeOriginal);
+
+ if (result && typeof (result as Promise).then === "function") {
+ return (result as Promise)
+ .then((value) => {
+ annotateResponse(span, resource, value, config.captureResponseMetadata);
+ finalizeSpan(span);
+ return value;
+ })
+ .catch((error: unknown) => {
+ finalizeSpan(span, error);
+ throw error;
+ });
+ }
+
+ annotateResponse(span, resource, result, config.captureResponseMetadata);
+ finalizeSpan(span);
+ return result;
+ } catch (error) {
+ finalizeSpan(span, error);
+ throw error;
+ }
+ };
+
+ (instrumented as { [INSTRUMENTED_METHOD_FLAG]?: true })[INSTRUMENTED_METHOD_FLAG] = true;
+ return instrumented;
+}
+
+function instrumentObject(
+ target: ResendLike,
+ path: readonly string[],
+ tracer: Tracer,
+ config: NormalizedConfig,
+): void {
+ if (!target || typeof target !== "object") {
+ return;
+ }
+
+ if (instrumentedObjects.has(target)) {
+ return;
+ }
+ instrumentedObjects.add(target);
+
+ const processedKeys = new Set();
+
+ for (const key of Reflect.ownKeys(target)) {
+ if (typeof key === "symbol") {
+ continue;
+ }
+ if (key === INSTRUMENTED_FLAG) {
+ continue;
+ }
+
+ processedKeys.add(key);
+
+ const descriptor = Object.getOwnPropertyDescriptor(target, key);
+ let value: unknown;
+
+ if (!descriptor || "value" in descriptor) {
+ value = (target as ResendLike)[key];
+ }
+
+ if (typeof value === "function") {
+ const original = value as AnyFunction;
+
+ if ((original as { [INSTRUMENTED_METHOD_FLAG]?: true })[INSTRUMENTED_METHOD_FLAG]) {
+ continue;
+ }
+
+ if (!config.shouldInstrument(path, key, original)) {
+ continue;
+ }
+
+ const wrapped = wrapMethod(original, path, key, tracer, config);
+
+ let replaced = false;
+ try {
+ replaced = Reflect.set(target, key, wrapped);
+ } catch {
+ replaced = false;
+ }
+
+ if (!replaced) {
+ Object.defineProperty(target, key, {
+ configurable: descriptor?.configurable ?? true,
+ enumerable: descriptor?.enumerable ?? true,
+ writable: descriptor?.writable ?? true,
+ value: wrapped,
+ });
+ }
+
+ continue;
+ }
+
+ if (value && typeof value === "object") {
+ instrumentObject(value as ResendLike, [...path, key], tracer, config);
+ continue;
+ }
+
+ if (descriptor && (descriptor.get || descriptor.set)) {
+ try {
+ const resolved = (target as ResendLike)[key];
+ if (resolved && typeof resolved === "object") {
+ instrumentObject(resolved as ResendLike, [...path, key], tracer, config);
+ }
+ } catch {
+ // Ignore accessor errors.
+ }
+ }
+ }
+
+ let prototype = Object.getPrototypeOf(target);
+ while (
+ prototype &&
+ prototype !== Object.prototype &&
+ prototype !== Function.prototype
+ ) {
+ for (const key of Reflect.ownKeys(prototype)) {
+ if (typeof key === "symbol" || key === "constructor") {
+ continue;
+ }
+ if (processedKeys.has(key)) {
+ continue;
+ }
+
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
+ if (!descriptor || typeof descriptor.value !== "function") {
+ continue;
+ }
+
+ const original = descriptor.value as AnyFunction;
+ if ((original as { [INSTRUMENTED_METHOD_FLAG]?: true })[INSTRUMENTED_METHOD_FLAG]) {
+ continue;
+ }
+
+ if (!config.shouldInstrument(path, key, original)) {
+ continue;
+ }
+
+ const wrapped = wrapMethod(original, path, key, tracer, config);
+
+ let replaced = false;
+ try {
+ replaced = Reflect.set(target, key, wrapped);
+ } catch {
+ replaced = false;
+ }
+
+ if (!replaced) {
+ Object.defineProperty(target, key, {
+ configurable: true,
+ enumerable: descriptor.enumerable ?? true,
+ writable: true,
+ value: wrapped,
+ });
+ }
+
+ processedKeys.add(key);
+ }
+
+ prototype = Object.getPrototypeOf(prototype);
+ }
+}
+
+export function instrumentResend(
+ client: TClient,
+ config?: InstrumentResendConfig,
+): TClient {
+ if (!client || typeof client !== "object") {
+ return client;
+ }
+
+ if ((client as InstrumentedResendLike)[INSTRUMENTED_FLAG]) {
+ return client;
+ }
+
+ const tracerName = config?.tracerName ?? DEFAULT_TRACER_NAME;
+ const tracer = config?.tracer ?? trace.getTracer(tracerName);
+
+ const normalizedConfig: NormalizedConfig = {
+ tracer,
+ tracerName,
+ captureRequestMetadata: config?.captureRequestMetadata ?? true,
+ captureResponseMetadata: config?.captureResponseMetadata ?? true,
+ shouldInstrument: config?.shouldInstrument ?? defaultShouldInstrument,
+ };
+
+ instrumentObject(client, [], tracer, normalizedConfig);
+
+ (client as InstrumentedResendLike)[INSTRUMENTED_FLAG] = true;
+
+ return client;
+}
diff --git a/packages/otel-resend/tsconfig.json b/packages/otel-resend/tsconfig.json
new file mode 100644
index 0000000..47fac92
--- /dev/null
+++ b/packages/otel-resend/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "lib": ["ES2020", "DOM"],
+ "outDir": "dist",
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "strict": false,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "declarationDir": "dist/types",
+ "stripInternal": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9dfeebe..119f4df 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -78,6 +78,30 @@ importers:
specifier: 0.33.0
version: 0.33.0(less@4.2.0)(sass@1.69.7)(stylus@0.59.0)
+ packages/otel-resend:
+ devDependencies:
+ '@opentelemetry/api':
+ specifier: ^1.9.0
+ version: 1.9.0
+ '@opentelemetry/sdk-trace-base':
+ specifier: ^2.1.0
+ version: 2.1.0(@opentelemetry/api@1.9.0)
+ '@types/node':
+ specifier: 18.15.11
+ version: 18.15.11
+ resend:
+ specifier: ^3.0.0
+ version: 3.5.0(react-dom@18.3.1(react@18.2.0))(react@18.2.0)
+ rimraf:
+ specifier: 3.0.2
+ version: 3.0.2
+ typescript:
+ specifier: ^5
+ version: 5.3.3
+ vitest:
+ specifier: 0.33.0
+ version: 0.33.0(less@4.2.0)(sass@1.69.7)(stylus@0.59.0)
+
packages:
'@adobe/css-tools@4.3.2':
@@ -304,6 +328,10 @@ packages:
'@hexagon/base64@1.1.28':
resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==}
+ '@isaacs/cliui@8.0.2':
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+
'@jest/schemas@29.6.3':
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -340,6 +368,9 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@one-ini/wasm@0.1.1':
+ resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
+
'@opentelemetry/api@1.9.0':
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
@@ -448,6 +479,20 @@ packages:
'@peculiar/x509@1.14.0':
resolution: {integrity: sha512-Yc4PDxN3OrxUPiXgU63c+ZRXKGE8YKF2McTciYhUHFtHVB0KMnjeFSU0qpztGhsp4P0uKix4+J2xEpIEDu8oXg==}
+ '@pkgjs/parseargs@0.11.0':
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+
+ '@react-email/render@0.0.16':
+ resolution: {integrity: sha512-wDaMy27xAq1cJHtSFptp0DTKPuV2GYhloqia95ub/DH9Dea1aWYsbdM918MOc/b/HvVS3w1z8DWzfAk13bGStQ==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: ^18.2.0
+ react-dom: ^18.2.0
+
+ '@selderee/plugin-htmlparser2@0.11.0':
+ resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==}
+
'@simplewebauthn/browser@13.2.0':
resolution: {integrity: sha512-N3fuA1AAnTo5gCStYoIoiasPccC+xPLx2YU88Dv0GeAmPQTWHETlZQq5xZ0DgUq1H9loXMWQH5qqUjcI7BHJ1A==}
@@ -506,6 +551,10 @@ packages:
'@vitest/utils@0.33.0':
resolution: {integrity: sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==}
+ abbrev@2.0.0:
+ resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
acorn-walk@8.3.1:
resolution: {integrity: sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==}
engines: {node: '>=0.4.0'}
@@ -523,6 +572,10 @@ packages:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
+ ansi-regex@6.2.2:
+ resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
+ engines: {node: '>=12'}
+
ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'}
@@ -535,6 +588,10 @@ packages:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
engines: {node: '>=10'}
+ ansi-styles@6.2.3:
+ resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
+ engines: {node: '>=12'}
+
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
@@ -618,6 +675,9 @@ packages:
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ brace-expansion@2.0.2:
+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+
braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
@@ -690,15 +750,26 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ commander@10.0.1:
+ resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
+ engines: {node: '>=14'}
+
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ config-chain@1.1.13:
+ resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+
copy-anything@2.0.6:
resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
cross-spawn@5.1.0:
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -739,6 +810,10 @@ packages:
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
engines: {node: '>=6'}
+ deepmerge@4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+
defaults@1.0.4:
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
@@ -765,6 +840,19 @@ packages:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
dotenv@8.6.0:
resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
engines: {node: '>=10'}
@@ -861,13 +949,28 @@ packages:
sqlite3:
optional: true
+ eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+ editorconfig@1.0.4:
+ resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==}
+ engines: {node: '>=14'}
+ hasBin: true
+
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
enquirer@2.4.1:
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
engines: {node: '>=8.6'}
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
errno@0.1.8:
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
hasBin: true
@@ -915,6 +1018,9 @@ packages:
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
engines: {node: '>=4'}
+ fast-deep-equal@2.0.1:
+ resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
+
fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
@@ -940,6 +1046,10 @@ packages:
for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+ foreground-child@3.3.1:
+ resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
+ engines: {node: '>=14'}
+
fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'}
@@ -984,6 +1094,10 @@ packages:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
+ glob@10.4.5:
+ resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ hasBin: true
+
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
@@ -1042,6 +1156,13 @@ packages:
hosted-git-info@2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
+ html-to-text@9.0.5:
+ resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==}
+ engines: {node: '>=14'}
+
+ htmlparser2@8.0.2:
+ resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
+
human-id@1.0.2:
resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==}
@@ -1076,6 +1197,9 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ ini@1.3.8:
+ resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+
internal-slot@1.0.6:
resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==}
engines: {node: '>= 0.4'}
@@ -1175,9 +1299,21 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+
jose@6.1.0:
resolution: {integrity: sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==}
+ js-beautify@1.15.4:
+ resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
+ engines: {node: '>=14'}
+ hasBin: true
+
+ js-cookie@3.0.5:
+ resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
+ engines: {node: '>=14'}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -1206,6 +1342,9 @@ packages:
resolution: {integrity: sha512-u/cAuTL4DRIiO2/g4vNGRgklEKNIj5Q3CG7RoUB5DV5SfEC2hMvPxKi0GWPmnzwL2ryIeud2VTcEEmqzTzEPNw==}
engines: {node: '>=20.0.0'}
+ leac@0.6.0:
+ resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==}
+
less@4.2.0:
resolution: {integrity: sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==}
engines: {node: '>=6'}
@@ -1240,6 +1379,9 @@ packages:
loupe@2.3.7:
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+
lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
@@ -1287,10 +1429,22 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ minimatch@9.0.1:
+ resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
minimist-options@4.1.0:
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
engines: {node: '>= 6'}
+ minipass@7.1.2:
+ resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
mixme@0.5.10:
resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==}
engines: {node: '>= 8.0.0'}
@@ -1324,6 +1478,11 @@ packages:
encoding:
optional: true
+ nopt@7.2.1:
+ resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ hasBin: true
+
normalize-package-data@2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
@@ -1384,6 +1543,9 @@ packages:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
+ package-json-from-dist@1.0.1:
+ resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+
parse-json@5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
@@ -1392,6 +1554,9 @@ packages:
resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
engines: {node: '>= 0.10'}
+ parseley@0.12.1:
+ resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -1400,9 +1565,17 @@ packages:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ path-scurry@1.11.1:
+ resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+ engines: {node: '>=16 || 14 >=14.18'}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -1413,6 +1586,9 @@ packages:
pathval@1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+ peberminta@0.9.0:
+ resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==}
+
pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
@@ -1484,6 +1660,9 @@ packages:
resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ proto-list@1.2.4:
+ resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+
prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
@@ -1504,9 +1683,17 @@ packages:
resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
engines: {node: '>=8'}
+ react-dom@18.3.1:
+ resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
+ peerDependencies:
+ react: ^18.3.1
+
react-is@18.2.0:
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
+ react-promise-suspense@0.3.4:
+ resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
+
react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@@ -1548,6 +1735,10 @@ packages:
require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
+ resend@3.5.0:
+ resolution: {integrity: sha512-bKu4LhXSecP6krvhfDzyDESApYdNfjirD5kykkT1xO0Cj9TKSiGh5Void4pGTs3Am+inSnp4dg0B5XzdwHBJOQ==}
+ engines: {node: '>=18'}
+
resolve-from@5.0.0:
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
@@ -1597,6 +1788,12 @@ packages:
sax@1.3.0:
resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==}
+ scheduler@0.23.2:
+ resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
+
+ selderee@0.11.0:
+ resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==}
+
semver@5.7.2:
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
hasBin: true
@@ -1624,10 +1821,18 @@ packages:
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
engines: {node: '>=0.10.0'}
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
shebang-regex@1.0.0:
resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
engines: {node: '>=0.10.0'}
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
side-channel@1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
@@ -1637,6 +1842,10 @@ packages:
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@@ -1689,6 +1898,10 @@ packages:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
+ string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+
string.prototype.trim@1.2.8:
resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
engines: {node: '>= 0.4'}
@@ -1703,6 +1916,10 @@ packages:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
+ strip-ansi@7.1.2:
+ resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
+ engines: {node: '>=12'}
+
strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
@@ -1952,6 +2169,11 @@ packages:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
why-is-node-running@2.2.2:
resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
engines: {node: '>=8'}
@@ -1965,6 +2187,10 @@ packages:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
+ wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@@ -2276,6 +2502,15 @@ snapshots:
'@hexagon/base64@1.1.28': {}
+ '@isaacs/cliui@8.0.2':
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: string-width@4.2.3
+ strip-ansi: 7.1.2
+ strip-ansi-cjs: strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: wrap-ansi@7.0.0
+
'@jest/schemas@29.6.3':
dependencies:
'@sinclair/typebox': 0.27.8
@@ -2316,6 +2551,8 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.16.0
+ '@one-ini/wasm@0.1.1': {}
+
'@opentelemetry/api@1.9.0': {}
'@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0)':
@@ -2478,6 +2715,22 @@ snapshots:
tslib: 2.8.1
tsyringe: 4.10.0
+ '@pkgjs/parseargs@0.11.0':
+ optional: true
+
+ '@react-email/render@0.0.16(react-dom@18.3.1(react@18.2.0))(react@18.2.0)':
+ dependencies:
+ html-to-text: 9.0.5
+ js-beautify: 1.15.4
+ react: 18.2.0
+ react-dom: 18.3.1(react@18.2.0)
+ react-promise-suspense: 0.3.4
+
+ '@selderee/plugin-htmlparser2@0.11.0':
+ dependencies:
+ domhandler: 5.0.3
+ selderee: 0.11.0
+
'@simplewebauthn/browser@13.2.0': {}
'@simplewebauthn/server@13.2.1':
@@ -2556,6 +2809,8 @@ snapshots:
loupe: 2.3.7
pretty-format: 29.7.0
+ abbrev@2.0.0: {}
+
acorn-walk@8.3.1: {}
acorn@8.15.0: {}
@@ -2564,6 +2819,8 @@ snapshots:
ansi-regex@5.0.1: {}
+ ansi-regex@6.2.2: {}
+
ansi-styles@3.2.1:
dependencies:
color-convert: 1.9.3
@@ -2574,6 +2831,8 @@ snapshots:
ansi-styles@5.2.0: {}
+ ansi-styles@6.2.3: {}
+
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
@@ -2658,6 +2917,10 @@ snapshots:
balanced-match: 1.0.2
concat-map: 0.0.1
+ brace-expansion@2.0.2:
+ dependencies:
+ balanced-match: 1.0.2
+
braces@3.0.2:
dependencies:
fill-range: 7.0.1
@@ -2750,8 +3013,15 @@ snapshots:
color-name@1.1.4: {}
+ commander@10.0.1: {}
+
concat-map@0.0.1: {}
+ config-chain@1.1.13:
+ dependencies:
+ ini: 1.3.8
+ proto-list: 1.2.4
+
copy-anything@2.0.6:
dependencies:
is-what: 3.14.1
@@ -2763,6 +3033,12 @@ snapshots:
shebang-command: 1.2.0
which: 1.3.1
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
csstype@3.1.3:
optional: true
@@ -2796,6 +3072,8 @@ snapshots:
dependencies:
type-detect: 4.0.8
+ deepmerge@4.3.1: {}
+
defaults@1.0.4:
dependencies:
clone: 1.0.4
@@ -2822,6 +3100,24 @@ snapshots:
dependencies:
path-type: 4.0.0
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
dotenv@8.6.0: {}
drizzle-orm@0.36.4(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(@types/react@18.2.46)(kysely@0.28.7)(postgres@3.4.7)(react@18.2.0):
@@ -2833,13 +3129,26 @@ snapshots:
postgres: 3.4.7
react: 18.2.0
+ eastasianwidth@0.2.0: {}
+
+ editorconfig@1.0.4:
+ dependencies:
+ '@one-ini/wasm': 0.1.1
+ commander: 10.0.1
+ minimatch: 9.0.1
+ semver: 7.5.4
+
emoji-regex@8.0.0: {}
+ emoji-regex@9.2.2: {}
+
enquirer@2.4.1:
dependencies:
ansi-colors: 4.1.3
strip-ansi: 6.0.1
+ entities@4.5.0: {}
+
errno@0.1.8:
dependencies:
prr: 1.0.1
@@ -2946,6 +3255,8 @@ snapshots:
iconv-lite: 0.4.24
tmp: 0.0.33
+ fast-deep-equal@2.0.1: {}
+
fast-glob@3.3.2:
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -2981,6 +3292,11 @@ snapshots:
dependencies:
is-callable: 1.2.7
+ foreground-child@3.3.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
+
fs-extra@7.0.1:
dependencies:
graceful-fs: 4.2.11
@@ -3029,6 +3345,15 @@ snapshots:
dependencies:
is-glob: 4.0.3
+ glob@10.4.5:
+ dependencies:
+ foreground-child: 3.3.1
+ jackspeak: 3.4.3
+ minimatch: 9.0.5
+ minipass: 7.1.2
+ package-json-from-dist: 1.0.1
+ path-scurry: 1.11.1
+
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@@ -3085,6 +3410,21 @@ snapshots:
hosted-git-info@2.8.9: {}
+ html-to-text@9.0.5:
+ dependencies:
+ '@selderee/plugin-htmlparser2': 0.11.0
+ deepmerge: 4.3.1
+ dom-serializer: 2.0.0
+ htmlparser2: 8.0.2
+ selderee: 0.11.0
+
+ htmlparser2@8.0.2:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ entities: 4.5.0
+
human-id@1.0.2: {}
iconv-lite@0.4.24:
@@ -3113,6 +3453,8 @@ snapshots:
inherits@2.0.4: {}
+ ini@1.3.8: {}
+
internal-slot@1.0.6:
dependencies:
get-intrinsic: 1.2.2
@@ -3207,8 +3549,24 @@ snapshots:
isexe@2.0.0: {}
+ jackspeak@3.4.3:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
jose@6.1.0: {}
+ js-beautify@1.15.4:
+ dependencies:
+ config-chain: 1.1.13
+ editorconfig: 1.0.4
+ glob: 10.4.5
+ js-cookie: 3.0.5
+ nopt: 7.2.1
+
+ js-cookie@3.0.5: {}
+
js-tokens@4.0.0: {}
js-yaml@3.14.1:
@@ -3230,6 +3588,8 @@ snapshots:
kysely@0.28.7: {}
+ leac@0.6.0: {}
+
less@4.2.0:
dependencies:
copy-anything: 2.0.6
@@ -3269,12 +3629,13 @@ snapshots:
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
- optional: true
loupe@2.3.7:
dependencies:
get-func-name: 2.0.2
+ lru-cache@10.4.3: {}
+
lru-cache@4.1.5:
dependencies:
pseudomap: 1.0.2
@@ -3328,12 +3689,22 @@ snapshots:
dependencies:
brace-expansion: 1.1.11
+ minimatch@9.0.1:
+ dependencies:
+ brace-expansion: 2.0.2
+
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.2
+
minimist-options@4.1.0:
dependencies:
arrify: 1.0.1
is-plain-obj: 1.1.0
kind-of: 6.0.3
+ minipass@7.1.2: {}
+
mixme@0.5.10: {}
mlly@1.4.2:
@@ -3359,6 +3730,10 @@ snapshots:
dependencies:
whatwg-url: 5.0.0
+ nopt@7.2.1:
+ dependencies:
+ abbrev: 2.0.0
+
normalize-package-data@2.5.0:
dependencies:
hosted-git-info: 2.8.9
@@ -3416,6 +3791,8 @@ snapshots:
p-try@2.2.0: {}
+ package-json-from-dist@1.0.1: {}
+
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.23.5
@@ -3426,18 +3803,32 @@ snapshots:
parse-node-version@1.0.1:
optional: true
+ parseley@0.12.1:
+ dependencies:
+ leac: 0.6.0
+ peberminta: 0.9.0
+
path-exists@4.0.0: {}
path-is-absolute@1.0.1: {}
+ path-key@3.1.1: {}
+
path-parse@1.0.7: {}
+ path-scurry@1.11.1:
+ dependencies:
+ lru-cache: 10.4.3
+ minipass: 7.1.2
+
path-type@4.0.0: {}
pathe@1.1.1: {}
pathval@1.1.1: {}
+ peberminta@0.9.0: {}
+
pg-int8@1.0.1: {}
pg-protocol@1.10.3: {}
@@ -3501,6 +3892,8 @@ snapshots:
ansi-styles: 5.2.0
react-is: 18.2.0
+ proto-list@1.2.4: {}
+
prr@1.0.1:
optional: true
@@ -3516,12 +3909,21 @@ snapshots:
quick-lru@4.0.1: {}
+ react-dom@18.3.1(react@18.2.0):
+ dependencies:
+ loose-envify: 1.4.0
+ react: 18.2.0
+ scheduler: 0.23.2
+
react-is@18.2.0: {}
+ react-promise-suspense@0.3.4:
+ dependencies:
+ fast-deep-equal: 2.0.1
+
react@18.2.0:
dependencies:
loose-envify: 1.4.0
- optional: true
read-pkg-up@7.0.1:
dependencies:
@@ -3567,6 +3969,13 @@ snapshots:
require-main-filename@2.0.0: {}
+ resend@3.5.0(react-dom@18.3.1(react@18.2.0))(react@18.2.0):
+ dependencies:
+ '@react-email/render': 0.0.16(react-dom@18.3.1(react@18.2.0))(react@18.2.0)
+ transitivePeerDependencies:
+ - react
+ - react-dom
+
resolve-from@5.0.0: {}
resolve@1.22.8:
@@ -3619,6 +4028,14 @@ snapshots:
sax@1.3.0:
optional: true
+ scheduler@0.23.2:
+ dependencies:
+ loose-envify: 1.4.0
+
+ selderee@0.11.0:
+ dependencies:
+ parseley: 0.12.1
+
semver@5.7.2: {}
semver@7.5.4:
@@ -3646,8 +4063,14 @@ snapshots:
dependencies:
shebang-regex: 1.0.0
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
shebang-regex@1.0.0: {}
+ shebang-regex@3.0.0: {}
+
side-channel@1.0.4:
dependencies:
call-bind: 1.0.5
@@ -3658,6 +4081,8 @@ snapshots:
signal-exit@3.0.7: {}
+ signal-exit@4.1.0: {}
+
slash@3.0.0: {}
smartwrap@2.0.2:
@@ -3712,6 +4137,12 @@ snapshots:
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
+ string-width@5.1.2:
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.2
+
string.prototype.trim@1.2.8:
dependencies:
call-bind: 1.0.5
@@ -3734,6 +4165,10 @@ snapshots:
dependencies:
ansi-regex: 5.0.1
+ strip-ansi@7.1.2:
+ dependencies:
+ ansi-regex: 6.2.2
+
strip-bom@3.0.0: {}
strip-indent@3.0.0:
@@ -3988,6 +4423,10 @@ snapshots:
dependencies:
isexe: 2.0.0
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
why-is-node-running@2.2.2:
dependencies:
siginfo: 2.0.0
@@ -4005,6 +4444,12 @@ snapshots:
string-width: 4.2.3
strip-ansi: 6.0.1
+ wrap-ansi@8.1.0:
+ dependencies:
+ ansi-styles: 6.2.3
+ string-width: 5.1.2
+ strip-ansi: 7.1.2
+
wrappy@1.0.2: {}
xtend@4.0.2: {}