irismail 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,157 +1,265 @@
1
1
  # IrisMail
2
2
 
3
- A modular, secure, and easy-to-use Email and OTP service for Next.js applications, with built-in Shadcn UI support.
3
+ [![npm version](https://img.shields.io/npm/v/irismail.svg)](https://www.npmjs.com/package/irismail)
4
+ [![npm downloads](https://img.shields.io/npm/dm/irismail.svg)](https://www.npmjs.com/package/irismail)
5
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-100%25-blue)](https://www.typescriptlang.org/)
7
+
8
+ A lightweight npm package for sending emails via Gmail and beautiful OTP input components for React.
4
9
 
5
10
  ## Features
6
11
 
7
- - 📧 **Email Service**: Simple wrapper around Nodemailer for sending emails.
8
- - 🔐 **Secure OTP**: Server-side OTP generation, encryption, and validation.
9
- - 🎨 **Shadcn UI**: Ready-to-use OTP Input component compatible with Shadcn UI.
10
- - **React Hook**: `useOTP` hook for managing timers, rate limiting, and resend cooldowns.
11
- - 🛡️ **Type-Safe**: Built with TypeScript.
12
+ - **Email Service**: Simple Gmail-based email sending with minimal configuration
13
+ - **OTP Input**: Beautiful, accessible OTP input components with copy-paste support
14
+ - **Themeable**: Dark and light themes built-in
15
+ - **Flexible**: Multiple sizes (sm/md/lg) and customizable styles via classNames API
16
+ - **Composable**: Build custom layouts with InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator
17
+ - **Easy to Use**: Minimal API surface - just a few props to get started
18
+ - **Type-Safe**: Built with TypeScript
19
+ - **Zero Config**: Just add your Gmail credentials - no SMTP configuration needed
12
20
 
13
21
  ## Installation
14
22
 
23
+ IrisMail works with all major package managers. No additional configuration is required.
24
+
15
25
  ```bash
16
26
  npm install irismail
17
- # or
18
- yarn add irismail
19
- # or
20
27
  pnpm add irismail
28
+ yarn add irismail
29
+ bun add irismail
21
30
  ```
22
31
 
23
- ## Usage
32
+ ## Package Exports
24
33
 
25
- ### 1. Server-Side Setup (API Routes)
34
+ | Import | Description |
35
+ |--------|-------------|
36
+ | `irismail/server` | Email service (IrisMail class and types) |
37
+ | `irismail/react` | OTP components (OTP, InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator) |
38
+ | `irismail` | All exports (server + react + utils) |
26
39
 
27
- Initialize the service with your email configuration and a secret key for encryption.
40
+ ## Email Service
41
+
42
+ Send emails with just your Gmail credentials:
28
43
 
29
44
  ```typescript
30
- // app/api/send-otp/route.ts
31
- import { IrisMailService } from 'irismail/server';
32
- import { NextResponse } from 'next/server';
33
-
34
- const irismail = new IrisMailService({
35
- email: {
36
- transport: {
37
- host: 'smtp.gmail.com',
38
- port: 587,
39
- auth: {
40
- user: process.env.GMAIL_USER,
41
- pass: process.env.GMAIL_PASS,
42
- },
43
- },
44
- defaults: {
45
- from: {
46
- name: 'My App',
47
- address: process.env.GMAIL_USER,
48
- },
49
- },
45
+ import { IrisMail } from 'irismail/server';
46
+
47
+ const mail = new IrisMail({
48
+ auth: {
49
+ user: process.env.GMAIL_USER!,
50
+ pass: process.env.GMAIL_APP_PASSWORD!,
50
51
  },
51
- secretKey: process.env.OTP_SECRET_KEY, // Must be 32 chars
52
52
  });
53
53
 
54
- export async function POST(req: Request) {
55
- const { email } = await req.json();
56
-
57
- // Generate and encrypt OTP
58
- const otp = irismail.otp.generateOTP();
59
- const encryptedOtp = irismail.otp.encryptOTP(otp);
60
-
61
- // Send email
62
- await irismail.email.sendEmail({
63
- to: email,
64
- subject: 'Your Verification Code',
65
- html: `<p>Your code is: <b>${otp}</b></p>`,
66
- });
67
-
68
- return NextResponse.json({ encryptedOtp });
69
- }
54
+ await mail.sendMail({
55
+ from: process.env.GMAIL_USER!,
56
+ to: 'user@example.com',
57
+ subject: 'Hello!',
58
+ html: '<h1>Welcome</h1><p>Thanks for signing up!</p>',
59
+ });
70
60
  ```
71
61
 
72
- ### 2. Client-Side Setup (React Component)
62
+ > **Note:** You'll need to generate a [Gmail App Password](https://support.google.com/accounts/answer/185833) for authentication.
73
63
 
74
- Use the `InputOTP` component and `useOTP` hook in your verification form.
64
+ ## OTP Input Component
65
+
66
+ ### Basic Usage
75
67
 
76
68
  ```tsx
77
- // components/verify-form.tsx
78
69
  'use client';
79
70
 
80
71
  import { useState } from 'react';
81
- import { InputOTP, InputOTPGroup, InputOTPSlot, useOTP } from 'irismail/react';
72
+ import { OTP } from 'irismail/react';
82
73
 
83
- export function VerifyForm({ email }) {
84
- const [otp, setOtp] = useState('');
85
- const { otpTimeLeft, resendTimeLeft, formatTime } = useOTP({ email });
74
+ export function VerifyForm() {
75
+ const [code, setCode] = useState('');
86
76
 
87
77
  return (
88
- <div className="space-y-4">
89
- <InputOTP
90
- maxLength={6}
91
- value={otp}
92
- onChange={setOtp}
93
- >
94
- <InputOTPGroup>
95
- <InputOTPSlot index={0} />
96
- <InputOTPSlot index={1} />
97
- <InputOTPSlot index={2} />
98
- <InputOTPSlot index={3} />
99
- <InputOTPSlot index={4} />
100
- <InputOTPSlot index={5} />
101
- </InputOTPGroup>
102
- </InputOTP>
103
-
104
- <div className="text-sm">
105
- Time remaining: {formatTime(otpTimeLeft)}
106
- </div>
107
- </div>
78
+ <OTP
79
+ value={code}
80
+ onChange={setCode}
81
+ onComplete={(value) => verify(value)}
82
+ />
108
83
  );
109
84
  }
110
85
  ```
111
86
 
112
- ## Local Testing
87
+ ### With Error State
88
+
89
+ ```tsx
90
+ <OTP
91
+ value={code}
92
+ onChange={setCode}
93
+ error={isInvalid}
94
+ />
95
+ ```
96
+
97
+ ### Custom Length
98
+
99
+ ```tsx
100
+ <OTP length={4} value={code} onChange={setCode} />
101
+ ```
102
+
103
+ ### Themes
104
+
105
+ Use the `theme` prop to switch between dark and light color schemes:
106
+
107
+ ```tsx
108
+ // Dark theme (default)
109
+ <OTP theme="dark" value={code} onChange={setCode} />
110
+
111
+ // Light theme - for light backgrounds
112
+ <OTP theme="light" value={code} onChange={setCode} />
113
+ ```
114
+
115
+ ### Sizes
116
+
117
+ Use the `slotSize` prop to change the slot dimensions:
118
+
119
+ ```tsx
120
+ <OTP slotSize="sm" value={code} onChange={setCode} />
121
+ <OTP slotSize="md" value={code} onChange={setCode} /> // default
122
+ <OTP slotSize="lg" value={code} onChange={setCode} />
123
+ ```
124
+
125
+ ### Separator & Grouping
126
+
127
+ Add visual separators and control grouping:
128
+
129
+ ```tsx
130
+ // With separator (auto groups: 3-3 for 6 digits)
131
+ <OTP separator value={code} onChange={setCode} />
132
+
133
+ // Custom group size (2-2-2 for 6 digits)
134
+ <OTP separator groupSize={2} value={code} onChange={setCode} />
135
+
136
+ // Stripe-style (3-3 for 6 digits)
137
+ <OTP length={6} separator groupSize={3} value={code} onChange={setCode} />
138
+ ```
139
+
140
+ ### Custom Styling (classNames API)
141
+
142
+ Use the `classNames` prop to customize individual parts:
143
+
144
+ ```tsx
145
+ <OTP
146
+ value={code}
147
+ onChange={setCode}
148
+ separator
149
+ groupSize={3}
150
+ classNames={{
151
+ slot: "rounded-none first:rounded-l-md last:rounded-r-md",
152
+ slotActive: "ring-2 ring-indigo-500 ring-offset-1 ring-offset-zinc-900",
153
+ separator: "mx-4",
154
+ separatorLine: "bg-indigo-500 w-4 h-0.5",
155
+ caret: "bg-indigo-400",
156
+ }}
157
+ />
158
+ ```
159
+
160
+ ### Composition Pattern
161
+
162
+ For custom layouts, use the composition components:
163
+
164
+ ```tsx
165
+ import {
166
+ InputOTP,
167
+ InputOTPGroup,
168
+ InputOTPSlot,
169
+ InputOTPSeparator,
170
+ } from 'irismail/react';
171
+
172
+ <InputOTP maxLength={6} value={code} onChange={setCode}>
173
+ <InputOTPGroup>
174
+ <InputOTPSlot index={0} />
175
+ <InputOTPSlot index={1} />
176
+ <InputOTPSlot index={2} />
177
+ </InputOTPGroup>
178
+ <InputOTPSeparator />
179
+ <InputOTPGroup>
180
+ <InputOTPSlot index={3} />
181
+ <InputOTPSlot index={4} />
182
+ <InputOTPSlot index={5} />
183
+ </InputOTPGroup>
184
+ </InputOTP>
185
+ ```
186
+
187
+ InputOTP and composition components support the same styling props: `theme`, `slotSize`, `error`, and `classNames`.
188
+
189
+ ## OTP Props
190
+
191
+ | Prop | Type | Default | Description |
192
+ |------|------|---------|-------------|
193
+ | `length` | number | 6 | Number of OTP digits |
194
+ | `value` | string | — | Controlled input value |
195
+ | `onChange` | (value: string) => void | — | Called when value changes |
196
+ | `onComplete` | (value: string) => void | — | Called when all digits entered |
197
+ | `theme` | "dark" \| "light" | "dark" | Color theme |
198
+ | `slotSize` | "sm" \| "md" \| "lg" | "md" | Size of the input slots |
199
+ | `separator` | boolean | false | Show separator between groups |
200
+ | `groupSize` | number | length / 2 | Number of slots per group when separator is enabled |
201
+ | `disabled` | boolean | false | Disable the input |
202
+ | `error` | boolean | false | Show error styling |
203
+ | `autoFocus` | boolean | false | Auto focus first slot |
204
+ | `name` | string | — | Name attribute for forms |
205
+ | `className` | string | — | Container className |
206
+ | `classNames` | OTPClassNames | — | Styles API for fine-grained customization |
207
+ | `pattern` | string | "^[0-9]*$" | Regex pattern to match input against |
208
+
209
+ ## ClassNames API
210
+
211
+ The `classNames` prop accepts an object with these keys for custom styling:
212
+
213
+ | Key | Description |
214
+ |-----|-------------|
215
+ | `root` | Root container element |
216
+ | `group` | Group wrapper containing slots |
217
+ | `slot` | Individual digit slot (base state) |
218
+ | `slotFilled` | Slot when it contains a digit |
219
+ | `slotActive` | Slot when focused/active |
220
+ | `slotError` | Slot in error state |
221
+ | `separator` | Separator container |
222
+ | `separatorLine` | The separator dash/line element |
223
+ | `caret` | Blinking caret cursor |
224
+
225
+ Works with both the `OTP` component and the composition components (`InputOTP`, etc.). OTP components work best with Tailwind CSS; use these class names to override or extend the default styles.
226
+
227
+ ## Documentation
228
+
229
+ For full documentation and interactive examples, run the docs site:
230
+
231
+ ```bash
232
+ npm run site
233
+ ```
234
+
235
+ ## Contributing
113
236
 
114
- Want to test the package locally before publishing? We've included a complete example app!
237
+ Contributions are welcome.
115
238
 
116
- 1. **Navigate to the example directory**:
239
+ 1. **Clone and install**
117
240
  ```bash
118
- cd example
241
+ git clone https://github.com/nitin-1926/irismail.git
242
+ cd irismail
243
+ npm install
119
244
  ```
120
245
 
121
- 2. **Set up environment variables**:
246
+ 2. **Build the package**
122
247
  ```bash
123
- cp .env.example .env.local
124
- # Edit .env.local with your Gmail credentials and secret key
248
+ npm run build
125
249
  ```
126
250
 
127
- 3. **Run the development server**:
251
+ 3. **Develop with watch mode**
128
252
  ```bash
129
253
  npm run dev
130
254
  ```
131
255
 
132
- 4. **Open [http://localhost:3000](http://localhost:3000)** to see:
133
- - Interactive OTP demo with email sending
134
- - Live documentation with code examples
135
- - All features working together
136
-
137
- See `example/README.md` for more details.
138
-
139
- ## Publishing to NPM
140
-
141
- 1. **Login to NPM**:
142
- ```bash
143
- npm login
144
- ```
145
-
146
- 2. **Build the package**:
147
- ```bash
148
- npm run build
149
- ```
256
+ 4. **Run the documentation site**
257
+ ```bash
258
+ npm run site
259
+ ```
260
+ Then open [http://localhost:3000](http://localhost:3000).
150
261
 
151
- 3. **Publish**:
152
- ```bash
153
- npm publish --access public
154
- ```
262
+ 5. **Submit changes**: Open a pull request with a clear description of the change. Ensure the build passes (`npm run build`) and the package works with the docs site.
155
263
 
156
264
  ## License
157
265
 
@@ -0,0 +1,42 @@
1
+ import {
2
+ __publicField
3
+ } from "./chunk-QZ7TP4HQ.mjs";
4
+
5
+ // src/server/email.ts
6
+ import nodemailer from "nodemailer";
7
+ var IrisMail = class {
8
+ constructor(config) {
9
+ __publicField(this, "transporter");
10
+ this.transporter = nodemailer.createTransport({
11
+ host: "smtp.gmail.com",
12
+ port: 587,
13
+ secure: false,
14
+ // true for 465, false for other ports
15
+ auth: config.auth
16
+ });
17
+ }
18
+ /**
19
+ * Send an email
20
+ * @param options - Email options (from, to, subject, html)
21
+ * @returns Promise with success status and messageId
22
+ */
23
+ async sendMail(options) {
24
+ const { from, to, subject, html } = options;
25
+ const text = html.replace(/<[^>]*>/g, "");
26
+ const info = await this.transporter.sendMail({
27
+ from,
28
+ to,
29
+ subject,
30
+ html,
31
+ text
32
+ });
33
+ return {
34
+ success: true,
35
+ messageId: info.messageId
36
+ };
37
+ }
38
+ };
39
+
40
+ export {
41
+ IrisMail
42
+ };
@@ -0,0 +1,208 @@
1
+ // src/react/components/input-otp.tsx
2
+ import { OTPInput, OTPInputContext } from "input-otp";
3
+ import * as React from "react";
4
+
5
+ // src/utils/constants.ts
6
+ import { clsx } from "clsx";
7
+ import { twMerge } from "tailwind-merge";
8
+ function cn(...inputs) {
9
+ return twMerge(clsx(inputs));
10
+ }
11
+
12
+ // src/react/components/input-otp.tsx
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ var slotSizeClasses = {
15
+ sm: "h-9 w-7 text-sm",
16
+ md: "h-11 w-9 text-base",
17
+ lg: "h-14 w-11 text-lg"
18
+ };
19
+ var caretSizeClasses = {
20
+ sm: "h-3 w-0.5",
21
+ md: "h-4 w-0.5",
22
+ lg: "h-5 w-0.5"
23
+ };
24
+ var themeClasses = {
25
+ dark: {
26
+ slot: {
27
+ base: "border-zinc-700 bg-zinc-800/50 text-white",
28
+ filled: "border-zinc-600 bg-zinc-800",
29
+ active: "border-zinc-500 bg-zinc-800",
30
+ error: "border-red-500/50 bg-red-500/5",
31
+ errorActive: "border-red-500/70"
32
+ },
33
+ caret: "bg-zinc-400",
34
+ separator: "bg-zinc-600"
35
+ },
36
+ light: {
37
+ slot: {
38
+ base: "border-zinc-300 bg-white text-zinc-900",
39
+ filled: "border-zinc-400 bg-zinc-50",
40
+ active: "border-zinc-500 bg-white",
41
+ error: "border-red-500/50 bg-red-50",
42
+ errorActive: "border-red-500/70"
43
+ },
44
+ caret: "bg-zinc-600",
45
+ separator: "bg-zinc-300"
46
+ }
47
+ };
48
+ var InputOTPStyleContext = React.createContext({
49
+ theme: "dark",
50
+ slotSize: "md"
51
+ });
52
+ var InputOTP = React.forwardRef(({ className, containerClassName, error, theme, slotSize, classNames, ...props }, ref) => {
53
+ const resolvedTheme = theme ?? "dark";
54
+ const resolvedSlotSize = slotSize ?? "md";
55
+ return /* @__PURE__ */ jsx(InputOTPStyleContext.Provider, { value: { error, theme: resolvedTheme, slotSize: resolvedSlotSize, classNames }, children: /* @__PURE__ */ jsx(
56
+ OTPInput,
57
+ {
58
+ ref,
59
+ containerClassName: cn(
60
+ "flex items-center gap-2 has-[:disabled]:opacity-50",
61
+ containerClassName,
62
+ classNames?.root
63
+ ),
64
+ className: cn("disabled:cursor-not-allowed", className),
65
+ ...props
66
+ }
67
+ ) });
68
+ });
69
+ InputOTP.displayName = "InputOTP";
70
+ var InputOTPGroup = React.forwardRef(({ className, ...props }, ref) => {
71
+ const { classNames } = React.useContext(InputOTPStyleContext);
72
+ return /* @__PURE__ */ jsx(
73
+ "div",
74
+ {
75
+ ref,
76
+ className: cn("flex items-center gap-2", className, classNames?.group),
77
+ ...props
78
+ }
79
+ );
80
+ });
81
+ InputOTPGroup.displayName = "InputOTPGroup";
82
+ var InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => {
83
+ const inputOTPContext = React.useContext(OTPInputContext);
84
+ const { error, theme, slotSize, classNames } = React.useContext(InputOTPStyleContext);
85
+ const slot = inputOTPContext.slots[index];
86
+ const { char, hasFakeCaret, isActive } = slot;
87
+ const colors = themeClasses[theme];
88
+ return /* @__PURE__ */ jsxs(
89
+ "div",
90
+ {
91
+ ref,
92
+ className: cn(
93
+ // Base styles
94
+ "relative flex items-center justify-center",
95
+ "border rounded-md",
96
+ "font-mono font-medium",
97
+ "transition-colors duration-150",
98
+ // Size
99
+ slotSizeClasses[slotSize],
100
+ // Default state (theme-aware)
101
+ colors.slot.base,
102
+ // Custom base slot class
103
+ classNames?.slot,
104
+ // Filled state
105
+ char && colors.slot.filled,
106
+ char && classNames?.slotFilled,
107
+ // Active/focus state
108
+ isActive && colors.slot.active,
109
+ isActive && classNames?.slotActive,
110
+ // Error state
111
+ error && colors.slot.error,
112
+ error && isActive && colors.slot.errorActive,
113
+ error && classNames?.slotError,
114
+ className
115
+ ),
116
+ "data-active": isActive,
117
+ "data-filled": Boolean(char),
118
+ "data-error": error,
119
+ ...props,
120
+ children: [
121
+ char,
122
+ hasFakeCaret && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: cn(
123
+ "animate-caret-blink rounded-full",
124
+ caretSizeClasses[slotSize],
125
+ colors.caret,
126
+ classNames?.caret
127
+ ) }) })
128
+ ]
129
+ }
130
+ );
131
+ });
132
+ InputOTPSlot.displayName = "InputOTPSlot";
133
+ var InputOTPSeparator = React.forwardRef(({ className, ...props }, ref) => {
134
+ const { theme, classNames } = React.useContext(InputOTPStyleContext);
135
+ const colors = themeClasses[theme];
136
+ return /* @__PURE__ */ jsx(
137
+ "div",
138
+ {
139
+ ref,
140
+ role: "separator",
141
+ className: cn("flex items-center justify-center", className, classNames?.separator),
142
+ ...props,
143
+ children: /* @__PURE__ */ jsx("span", { className: cn("w-3 h-0.5 rounded-full", colors.separator, classNames?.separatorLine) })
144
+ }
145
+ );
146
+ });
147
+ InputOTPSeparator.displayName = "InputOTPSeparator";
148
+ var OTP = React.forwardRef(
149
+ ({
150
+ length = 6,
151
+ value,
152
+ onChange,
153
+ onComplete,
154
+ disabled,
155
+ error,
156
+ autoFocus,
157
+ name,
158
+ className,
159
+ pattern = "^[0-9]*$",
160
+ theme,
161
+ slotSize,
162
+ separator = false,
163
+ groupSize,
164
+ classNames
165
+ }, ref) => {
166
+ const resolvedTheme = theme ?? "dark";
167
+ const resolvedSlotSize = slotSize ?? "md";
168
+ const slotIndices = Array.from({ length }, (_, i) => i);
169
+ const effectiveGroupSize = groupSize ?? (separator ? Math.ceil(length / 2) : length);
170
+ const groups = [];
171
+ for (let i = 0; i < length; i += effectiveGroupSize) {
172
+ groups.push(slotIndices.slice(i, i + effectiveGroupSize));
173
+ }
174
+ return /* @__PURE__ */ jsx(
175
+ InputOTP,
176
+ {
177
+ ref,
178
+ maxLength: length,
179
+ value,
180
+ onChange,
181
+ onComplete,
182
+ disabled,
183
+ error,
184
+ autoFocus,
185
+ name,
186
+ pattern,
187
+ containerClassName: className,
188
+ theme: resolvedTheme,
189
+ slotSize: resolvedSlotSize,
190
+ classNames,
191
+ children: groups.map((group, groupIndex) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
192
+ groupIndex > 0 && separator && /* @__PURE__ */ jsx(InputOTPSeparator, {}),
193
+ /* @__PURE__ */ jsx(InputOTPGroup, { children: group.map((index) => /* @__PURE__ */ jsx(InputOTPSlot, { index }, index)) })
194
+ ] }, groupIndex))
195
+ }
196
+ );
197
+ }
198
+ );
199
+ OTP.displayName = "OTP";
200
+
201
+ export {
202
+ cn,
203
+ InputOTP,
204
+ InputOTPGroup,
205
+ InputOTPSlot,
206
+ InputOTPSeparator,
207
+ OTP
208
+ };
package/dist/index.d.mts CHANGED
@@ -1,16 +1,9 @@
1
- export { EmailConfig, EmailService, IrisMailService, OTPData, OTPService, SendEmailOptions, decrypt, encrypt } from './server/index.mjs';
2
- export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, useOTP } from './react/index.mjs';
1
+ export { IrisMail, IrisMailConfig, SendMailOptions, SendMailResult } from './server/index.mjs';
2
+ export { InputOTP, InputOTPGroup, InputOTPProps, InputOTPSeparator, InputOTPSlot, OTP, OTPClassNames, OTPProps, OTPSize, OTPTheme } from './react/index.mjs';
3
3
  import { ClassValue } from 'clsx';
4
4
  import 'input-otp';
5
5
  import 'react';
6
6
 
7
7
  declare function cn(...inputs: ClassValue[]): string;
8
- declare const OTP_DEFAULTS: {
9
- LENGTH: number;
10
- EXPIRY_MINUTES: number;
11
- RESEND_COOLDOWN_SECONDS: number;
12
- MAX_ATTEMPTS: number;
13
- RATE_LIMIT_RESET_HOURS: number;
14
- };
15
8
 
16
- export { OTP_DEFAULTS, cn };
9
+ export { cn };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,9 @@
1
- export { EmailConfig, EmailService, IrisMailService, OTPData, OTPService, SendEmailOptions, decrypt, encrypt } from './server/index.js';
2
- export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, useOTP } from './react/index.js';
1
+ export { IrisMail, IrisMailConfig, SendMailOptions, SendMailResult } from './server/index.js';
2
+ export { InputOTP, InputOTPGroup, InputOTPProps, InputOTPSeparator, InputOTPSlot, OTP, OTPClassNames, OTPProps, OTPSize, OTPTheme } from './react/index.js';
3
3
  import { ClassValue } from 'clsx';
4
4
  import 'input-otp';
5
5
  import 'react';
6
6
 
7
7
  declare function cn(...inputs: ClassValue[]): string;
8
- declare const OTP_DEFAULTS: {
9
- LENGTH: number;
10
- EXPIRY_MINUTES: number;
11
- RESEND_COOLDOWN_SECONDS: number;
12
- MAX_ATTEMPTS: number;
13
- RATE_LIMIT_RESET_HOURS: number;
14
- };
15
8
 
16
- export { OTP_DEFAULTS, cn };
9
+ export { cn };