volter 0.0.174 → 0.0.177

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,2 +1,309 @@
1
+ <img src="/public/cover.png" alt="Volter" />
2
+
1
3
  # Volter
2
- Secure, lightweight, and user-friendly modern JavaScript toolchain optimized for performance and minimalism.
4
+
5
+ Secure, lightweight session management and authentication library for modern JavaScript applications. Built with Bun runtime optimization, it provides Redis-backed session storage, email verification, encryption utilities, and structured error handling.
6
+
7
+ ## Features
8
+
9
+ - **Session Management** - Redis-backed sessions with secure token validation
10
+ - **Email Verification** - PIN-based verification with Resend integration
11
+ - **Cryptography** - AES-GCM encryption, RSA key pairs, ECDSA signatures
12
+ - **Security Utilities** - Secure ID generation, hashing, and validation
13
+ - **Error Handling** - Structured error codes and custom error classes
14
+ - **TypeScript Support** - Full type definitions included
15
+ - **Bun Optimized** - Leverages Bun's built-in Redis and crypto APIs
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install volter
21
+ ```
22
+ ```bash
23
+ bun add volter
24
+ ```
25
+
26
+ ### Required Dependencies
27
+
28
+ - **Redis Server** - For session storage
29
+ - **Resend API Key** - For email verification (optional)
30
+ - **Bun Runtime** - Recommended for optimal performance
31
+ - **Node.js** - Also supported (v18+)
32
+
33
+ ## Quick Start
34
+
35
+ ```typescript
36
+ import { Sessions } from "volter";
37
+
38
+ // Initialize sessions with Redis
39
+ const sessions = new Sessions({
40
+ expiry: 2592000, // 30 days in seconds
41
+ });
42
+
43
+ // Create session for user
44
+ const session = await sessions.create("user-123");
45
+ console.log("Session token:", session.token);
46
+
47
+ // Validate session
48
+ const userId = await sessions.validate(session.token);
49
+ console.log("User ID:", userId); // 'user-123'
50
+ ```
51
+
52
+ ## API Overview
53
+
54
+ ### Sessions Class
55
+
56
+ Complete session lifecycle management with Redis backend.
57
+
58
+ ```typescript
59
+ import { RedisClient } from "bun"
60
+ import { Sessions } from "volter";
61
+
62
+ const redis = new RedisClient(Bun.env.REDIS_URL)
63
+
64
+ const sessions = new Sessions({
65
+ store: redis, // Optional, defaults to Bun.redis
66
+ expiry: 2592000, // 30 days in seconds
67
+ createID: crypto.randomUUID, // Optional custom ID generator
68
+ });
69
+
70
+ // Create new session
71
+ const session = await sessions.create("user-id");
72
+
73
+ // Validate session token
74
+ const userId = await sessions.validate(token);
75
+
76
+ // Get session details
77
+ const details = await sessions.get(token);
78
+
79
+ // List all user sessions
80
+ const userSessions = await sessions.list("user-id");
81
+
82
+ // Revoke session
83
+ await sessions.revoke(token);
84
+ ```
85
+
86
+ ### Email Verification (e1T)
87
+
88
+ PIN-based email verification with Resend integration.
89
+
90
+ ```typescript
91
+ import { e1T } from "volter";
92
+ import { Resend } from "resend";
93
+
94
+ const e1t = new e1T({
95
+ resend: new Resend("re_xxxxxxxxx"),
96
+ expiry: 300, // 5 minutes
97
+ attempts: 5, // Max verification attempts
98
+ template: (email, code) => ({
99
+ from: "noreply@app.dev",
100
+ to: email,
101
+ subject: `${code}: is your verification code.`,
102
+ text: `Enter ${code} to verify your email. For your security, do not share.`,
103
+ }),
104
+ });
105
+
106
+ // Send verification code
107
+ const result = await e1t.send("user@app.dev");
108
+ console.log("Verification code:", result.code);
109
+
110
+ // Verify code
111
+ const isValid = await e1t.verify("user@app.dev", "855 004");
112
+ ```
113
+
114
+ ### Cryptography Utilities
115
+
116
+ Secure encryption, signing, and key management.
117
+
118
+ ```typescript
119
+ import {
120
+ cipher,
121
+ decipher,
122
+ sign,
123
+ verifySign,
124
+ generateECDSAKeyPair,
125
+ hash,
126
+ } from "volter";
127
+
128
+ // AES-GCM encryption
129
+ const encrypted = await cipher("secret data", "encryption-key");
130
+ const decrypted = await decipher(encrypted, "encryption-key");
131
+
132
+ // Digital signatures
133
+ const keyPair = await generateECDSAKeyPair();
134
+ const signature = await sign("message to sign", keyPair.privateKey);
135
+ const isValid = await verifySign(
136
+ "message to sign",
137
+ signature,
138
+ keyPair.publicKey,
139
+ );
140
+
141
+ // Secure hashing
142
+ const hashed = hash("password", "salt");
143
+ ```
144
+
145
+ ### Error Handling
146
+
147
+ Structured error codes and custom error classes.
148
+
149
+ ```typescript
150
+ import { ServerError, ErrorCodes, ValidationError } from "volter";
151
+
152
+ // Custom server error
153
+ throw new ServerError("User not found", {
154
+ code: ErrorCodes.RESOURCE_NOT_FOUND,
155
+ at: ["UserService", "getUserById"],
156
+ });
157
+
158
+ // Validation with Zod
159
+ import { z } from "zod";
160
+ const schema = z.string().email();
161
+ try {
162
+ schema.parse("invalid-email");
163
+ } catch (error) {
164
+ throw new ValidationError("Invalid email format");
165
+ }
166
+ ```
167
+
168
+ ## Configuration
169
+
170
+ ### Redis Setup
171
+
172
+ ```typescript
173
+ // Using default Bun Redis
174
+ const sessions = new Sessions();
175
+
176
+ // Using custom Redis client
177
+ const sessions = new Sessions({
178
+ store: new RedisClient({
179
+ host: "localhost",
180
+ port: 6379,
181
+ password: "your-password",
182
+ }),
183
+ });
184
+ ```
185
+
186
+ ### Resend Email Setup
187
+
188
+ ```typescript
189
+ import { Resend } from "resend";
190
+
191
+ const emailVerify = new e1T({
192
+ resend: new Resend(process.env.RESEND_API_KEY),
193
+ template: (email, code) => ({
194
+ from: process.env.FROM_EMAIL,
195
+ to: email,
196
+ subject: `Verify your account - Code: ${code}`,
197
+ html: `<h1>Your verification code is: <strong>${code}</strong></h1>`,
198
+ }),
199
+ });
200
+ ```
201
+
202
+ ## Security Best Practices
203
+
204
+ - Always use HTTPS in production
205
+ - Store sensitive keys in environment variables
206
+ - Set appropriate session expiry times
207
+ - Implement rate limiting for verification attempts
208
+ - Use secure, random session tokens
209
+ - Regularly rotate encryption keys
210
+
211
+ ## TypeScript Support
212
+
213
+ Volter includes full TypeScript definitions:
214
+
215
+ ```typescript
216
+ import {
217
+ Sessions,
218
+ Session,
219
+ SessionPayload,
220
+ e1T,
221
+ ServerError,
222
+ ErrorCodes,
223
+ } from "volter";
224
+
225
+ // Full type safety and IntelliSense support
226
+ const sessions: Sessions = new Sessions();
227
+ const session: Session = await sessions.get(token);
228
+ ```
229
+
230
+ ## Examples
231
+
232
+ ### Web Server Integration
233
+
234
+ ```typescript
235
+ import { Sessions } from "volter";
236
+
237
+ const sessions = new Sessions();
238
+
239
+ // Middleware for session validation
240
+ export async function requireAuth(req: Request) {
241
+ const token = req.headers.get("authorization")?.replace("Bearer ", "");
242
+ if (!token)
243
+ throw new ServerError("No token provided", {
244
+ code: ErrorCodes.AUTHENTICATION_FAILED,
245
+ });
246
+
247
+ const userId = await sessions.validate(token);
248
+ if (!userId)
249
+ throw new ServerError("Invalid token", { code: ErrorCodes.INVALID_TOKEN });
250
+
251
+ return userId;
252
+ }
253
+ ```
254
+
255
+ ### Complete Auth Flow
256
+
257
+ ```typescript
258
+ import { Sessions, e1T } from "volter";
259
+
260
+ const sessions = new Sessions();
261
+ const emailVerify = new e1T();
262
+
263
+ // 1. Send verification code
264
+ await emailVerify.send(email);
265
+
266
+ // 2. Verify email and create session
267
+ const isValid = await emailVerify.verify(email, code);
268
+ if (isValid) {
269
+ const session = await sessions.create(userId);
270
+ return { token: session.token };
271
+ }
272
+ ```
273
+
274
+ ## Contributing
275
+
276
+ We welcome contributions! Please follow these steps:
277
+
278
+ 1. Fork the repository
279
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
280
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
281
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
282
+ 5. Open a Pull Request
283
+
284
+ ### Development Setup
285
+
286
+ ```bash
287
+ # Clone the repository
288
+ git clone https://github.com/your-org/volter.git
289
+ cd volter
290
+
291
+ # Install dependencies
292
+ bun install
293
+
294
+ # Run tests
295
+ bun test
296
+
297
+ # Build the project
298
+ bun run build
299
+ ```
300
+
301
+ ## License
302
+
303
+ The Modlin Distributable License (MDL) © [Modlin](https://modlin.dev) - See [LICENSE](LICENSE) file for details
304
+
305
+ ## Support
306
+
307
+ - [Documentation](https://modlin.dev/volter/docs)
308
+ - [Issue Tracker](https://github.com/modlin-dev/volter/issues)
309
+ - [Email Support](mailto:volter@modlin.dev)
package/dist/crypto.js CHANGED
@@ -1,2 +1 @@
1
- // @bun
2
- var c=Object.create;var{getPrototypeOf:s,defineProperty:o,getOwnPropertyNames:p}=Object;var u=Object.prototype.hasOwnProperty;var A=(e,t,r)=>{r=e!=null?c(s(e)):{};let n=t||!e||!e.__esModule?o(r,"default",{value:e,enumerable:!0}):r;for(let a of p(e))if(!u.call(n,a))o(n,a,{get:()=>e[a],enumerable:!0});return n};var d=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var m=(e,t)=>{for(var r in t)o(e,r,{get:t[r],enumerable:!0,configurable:!0,set:(n)=>t[r]=()=>n})};var x=import.meta.require;function f(e,t){return new Bun.CryptoHasher("sha256",t).update(e).digest("hex")}async function i(e){if(e){if(e instanceof CryptoKey)return e;if(e instanceof Uint8Array){if(e.length===32)return await crypto.subtle.importKey("raw",e,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"]);return await crypto.subtle.importKey("raw",e,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"])}if(e.length===64)return await crypto.subtle.importKey("raw",Uint8Array.fromHex(e),{name:"AES-GCM",length:256},!0,["encrypt","decrypt"]);else return await crypto.subtle.importKey("raw",Uint8Array.fromHex(f(e)),{name:"AES-GCM",length:256},!0,["encrypt","decrypt"])}else return await crypto.subtle.generateKey({name:"AES-GCM",length:256},!0,["encrypt","decrypt"])}async function C(e,t){let r=await crypto.subtle.exportKey(t,e);return new Uint8Array(r).toBase64()}async function K(){return await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!0,["sign","verify"])}async function l(e){return await crypto.subtle.exportKey("jwk",e)}async function w(e,t){return await crypto.subtle.importKey("jwk",e,{name:"ECDSA",namedCurve:"P-256"},!0,t)}async function b(e,t){let r=new TextEncoder().encode(e),n=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,r);return new Uint8Array(n)}async function h(e,t,r){let n=new TextEncoder().encode(e);return await crypto.subtle.verify({name:"ECDSA",hash:{name:"SHA-256"}},r,t,n)}async function E(e,t){let n=new TextEncoder().encode(e),a=crypto.getRandomValues(new Uint8Array(12)),y=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},await i(t),n);return{text:new Uint8Array(y).toHex(),iv:a,buffer:y}}async function S(e,t){let r=new TextDecoder,n=await crypto.subtle.decrypt({name:"AES-GCM",iv:e.iv},await i(t),Uint8Array.fromHex(e.text));return r.decode(n)}async function P(){return await crypto.subtle.generateKey({name:"RSA-OAEP",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:{name:"SHA-256"}},!0,["encrypt","decrypt"])}async function U(e,t){let r=new TextEncoder().encode(e),n=await crypto.subtle.encrypt({name:"RSA-OAEP"},t,r);return new Uint8Array(n)}async function v(e,t){let r=await crypto.subtle.decrypt({name:"RSA-OAEP"},t,e);return new TextDecoder().decode(r)}export{h as verifySign,b as sign,P as keypair,w as importJWK,f as hash,K as generateECDSAKeyPair,C as exportKey,l as exportJWK,U as encrypt,v as decrypt,S as decipher,i as cryptoKey,E as cipher};
1
+ var u=Object.create;var{getPrototypeOf:f,defineProperty:o,getOwnPropertyNames:c,getOwnPropertyDescriptor:A}=Object,s=Object.prototype.hasOwnProperty;var m=(e,t,r)=>{r=e!=null?u(f(e)):{};let n=t||!e||!e.__esModule?o(r,"default",{value:e,enumerable:!0}):r;for(let a of c(e))if(!s.call(n,a))o(n,a,{get:()=>e[a],enumerable:!0});return n},i=new WeakMap,x=(e)=>{var t=i.get(e),r;if(t)return t;if(t=o({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")c(e).map((n)=>!s.call(t,n)&&o(t,n,{get:()=>e[n],enumerable:!(r=A(e,n))||r.enumerable}));return i.set(e,t),t},g=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var C=(e,t)=>{for(var r in t)o(e,r,{get:t[r],enumerable:!0,configurable:!0,set:(n)=>t[r]=()=>n})};var K=(e,t)=>()=>(e&&(t=e(e=0)),t);var l=((e)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});function d(e,t){return new Bun.CryptoHasher("sha256",t).update(e).digest("hex")}async function p(e){if(e){if(e instanceof CryptoKey)return e;if(e instanceof Uint8Array){if(e.length===32)return await crypto.subtle.importKey("raw",e,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"]);return await crypto.subtle.importKey("raw",e,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"])}if(e.length===64)return await crypto.subtle.importKey("raw",Uint8Array.fromHex(e),{name:"AES-GCM",length:256},!0,["encrypt","decrypt"]);else return await crypto.subtle.importKey("raw",Uint8Array.fromHex(d(e)),{name:"AES-GCM",length:256},!0,["encrypt","decrypt"])}else return await crypto.subtle.generateKey({name:"AES-GCM",length:256},!0,["encrypt","decrypt"])}async function b(e,t){let r=await crypto.subtle.exportKey(t,e);return new Uint8Array(r).toBase64()}async function h(){return await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!0,["sign","verify"])}async function E(e){return await crypto.subtle.exportKey("jwk",e)}async function S(e,t){return await crypto.subtle.importKey("jwk",e,{name:"ECDSA",namedCurve:"P-256"},!0,t)}async function P(e,t){let r=new TextEncoder().encode(e),n=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,r);return new Uint8Array(n)}async function U(e,t,r){let n=new TextEncoder().encode(e);return await crypto.subtle.verify({name:"ECDSA",hash:{name:"SHA-256"}},r,t,n)}async function v(e,t){let n=new TextEncoder().encode(e),a=crypto.getRandomValues(new Uint8Array(12)),y=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},await p(t),n);return{text:new Uint8Array(y).toHex(),iv:a,buffer:y}}async function B(e,t){let r=new TextDecoder,n=await crypto.subtle.decrypt({name:"AES-GCM",iv:e.iv},await p(t),Uint8Array.fromHex(e.text));return r.decode(n)}async function T(){return await crypto.subtle.generateKey({name:"RSA-OAEP",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:{name:"SHA-256"}},!0,["encrypt","decrypt"])}async function H(e,t){let r=new TextEncoder().encode(e),n=await crypto.subtle.encrypt({name:"RSA-OAEP"},t,r);return new Uint8Array(n)}async function D(e,t){let r=await crypto.subtle.decrypt({name:"RSA-OAEP"},t,e);return new TextDecoder().decode(r)}export{U as verifySign,P as sign,T as keypair,S as importJWK,d as hash,h as generateECDSAKeyPair,b as exportKey,E as exportJWK,H as encrypt,D as decrypt,B as decipher,p as cryptoKey,v as cipher};