@hedystia/validations 1.2.8 → 1.2.10
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/dist/index.d.ts +80 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/readme.md +167 -167
package/dist/index.d.ts
CHANGED
|
@@ -58,8 +58,12 @@ declare class StringSchemaType extends BaseSchema<unknown, string> {
|
|
|
58
58
|
readonly type: SchemaPrimitive;
|
|
59
59
|
private _validateEmail;
|
|
60
60
|
private _validatePhone;
|
|
61
|
+
private _minLength?;
|
|
62
|
+
private _maxLength?;
|
|
61
63
|
constructor();
|
|
62
64
|
primitive(): SchemaPrimitive;
|
|
65
|
+
minLength(n: number): StringSchemaType;
|
|
66
|
+
maxLength(n: number): StringSchemaType;
|
|
63
67
|
email(): StringSchemaType;
|
|
64
68
|
phone(): StringSchemaType;
|
|
65
69
|
readonly "~standard": StandardSchemaV1.Props<unknown, string>;
|
|
@@ -68,8 +72,12 @@ declare class StringSchemaType extends BaseSchema<unknown, string> {
|
|
|
68
72
|
}
|
|
69
73
|
declare class NumberSchemaType extends BaseSchema<unknown, number> {
|
|
70
74
|
readonly type: SchemaPrimitive;
|
|
75
|
+
private _min?;
|
|
76
|
+
private _max?;
|
|
71
77
|
constructor();
|
|
72
78
|
primitive(): SchemaPrimitive;
|
|
79
|
+
min(n: number): NumberSchemaType;
|
|
80
|
+
max(n: number): NumberSchemaType;
|
|
73
81
|
readonly "~standard": StandardSchemaV1.Props<unknown, number>;
|
|
74
82
|
}
|
|
75
83
|
declare class BooleanSchemaType extends BaseSchema<unknown, boolean> {
|
|
@@ -126,21 +134,93 @@ declare class ObjectSchemaType<T extends Record<string, unknown>> extends BaseSc
|
|
|
126
134
|
}
|
|
127
135
|
type AnySchema = SchemaPrimitive | BaseSchema<any, any> | SchemaDefinition;
|
|
128
136
|
declare function toStandard<T>(schema: AnySchema): Schema<unknown, T>;
|
|
137
|
+
/**
|
|
138
|
+
* Create standard schema types
|
|
139
|
+
* @returns {typeof h} Standard schema types
|
|
140
|
+
*/
|
|
129
141
|
declare const h: {
|
|
142
|
+
/**
|
|
143
|
+
* Create string schema type
|
|
144
|
+
* @returns {StringSchemaType} String schema type
|
|
145
|
+
*/
|
|
130
146
|
string: () => StringSchemaType;
|
|
147
|
+
/**
|
|
148
|
+
* Create number schema type
|
|
149
|
+
* @returns {NumberSchemaType} Number schema type
|
|
150
|
+
*/
|
|
131
151
|
number: () => NumberSchemaType;
|
|
152
|
+
/**
|
|
153
|
+
* Create boolean schema type
|
|
154
|
+
* @returns {BooleanSchemaType} Boolean schema type
|
|
155
|
+
*/
|
|
132
156
|
boolean: () => BooleanSchemaType;
|
|
157
|
+
/**
|
|
158
|
+
* Create null schema type
|
|
159
|
+
* @returns {NullSchemaType} Null schema type
|
|
160
|
+
*/
|
|
133
161
|
null: () => NullSchemaType;
|
|
162
|
+
/**
|
|
163
|
+
* Create any schema type
|
|
164
|
+
* @returns {AnySchemaType} Any schema type
|
|
165
|
+
*/
|
|
134
166
|
any: () => AnySchemaType;
|
|
167
|
+
/**
|
|
168
|
+
* Create literal schema type
|
|
169
|
+
* @param {T} value - Literal value
|
|
170
|
+
* @returns {LiteralSchema<T>} Literal schema type
|
|
171
|
+
*/
|
|
135
172
|
literal: <T extends string | number | boolean>(value: T) => LiteralSchema<T>;
|
|
173
|
+
/**
|
|
174
|
+
* Create object schema type
|
|
175
|
+
* @param {S} [schemaDef] - Schema definition
|
|
176
|
+
* @returns {ObjectSchemaType<InferObject<S>>} Object schema type
|
|
177
|
+
*/
|
|
136
178
|
object: <S extends SchemaDefinition>(schemaDef?: S) => ObjectSchemaType<InferObject<S>>;
|
|
179
|
+
/**
|
|
180
|
+
* Create array schema type
|
|
181
|
+
* @param {S} schema - Schema
|
|
182
|
+
* @returns {ArraySchema<unknown, InferSchema<S>[]>} Array schema type
|
|
183
|
+
*/
|
|
137
184
|
array: <S extends AnySchema>(schema: S) => ArraySchema<unknown, InferSchema<S>[]>;
|
|
185
|
+
/**
|
|
186
|
+
* Create enum schema type
|
|
187
|
+
* @param {T} values - Enum values
|
|
188
|
+
* @returns {EnumSchema<unknown, T[number]>} Enum schema type
|
|
189
|
+
*/
|
|
138
190
|
enum: <T extends readonly [any, ...any[]]>(values: T) => EnumSchema<unknown, T[number]>;
|
|
191
|
+
/**
|
|
192
|
+
* Create optional schema type
|
|
193
|
+
* @param {S} schema - Schema
|
|
194
|
+
* @returns {OptionalSchema<unknown, InferSchema<S> | undefined>} Optional schema type
|
|
195
|
+
*/
|
|
139
196
|
optional: <S extends AnySchema>(schema: S) => OptionalSchema<unknown, InferSchema<S> | undefined>;
|
|
197
|
+
/**
|
|
198
|
+
* Create options schema type
|
|
199
|
+
* @param {S} schemas - Schemas
|
|
200
|
+
* @returns {UnionSchema<unknown, InferSchema<S[number]>>} Options schema type
|
|
201
|
+
*/
|
|
140
202
|
options: <S extends AnySchema[]>(...schemas: S) => UnionSchema<unknown, InferSchema<S[number]>>;
|
|
203
|
+
/**
|
|
204
|
+
* Create instance of schema type
|
|
205
|
+
* @param {C} constructor - Constructor function
|
|
206
|
+
* @returns {InstanceOfSchema<unknown, InstanceType<C>>} Instance of schema type
|
|
207
|
+
*/
|
|
141
208
|
instanceOf: <C extends new (...args: any[]) => any>(constructor: C) => InstanceOfSchema<unknown, InstanceType<C>>;
|
|
209
|
+
/**
|
|
210
|
+
* Create email schema type
|
|
211
|
+
* @returns {StringSchemaType} Email schema type
|
|
212
|
+
*/
|
|
142
213
|
email: () => StringSchemaType;
|
|
214
|
+
/**
|
|
215
|
+
* Create phone schema type
|
|
216
|
+
* @returns {StringSchemaType} Phone schema type
|
|
217
|
+
*/
|
|
143
218
|
phone: () => StringSchemaType;
|
|
219
|
+
/**
|
|
220
|
+
* Convert schema to standard schema
|
|
221
|
+
* @param {AnySchema} schema - Schema
|
|
222
|
+
* @returns {Schema<unknown, any>} Standard schema
|
|
223
|
+
*/
|
|
144
224
|
toStandard: typeof toStandard;
|
|
145
225
|
};
|
|
146
226
|
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var b=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var V=(a,e)=>{for(var n in e)b(a,n,{get:e[n],enumerable:!0})},_=(a,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of T(e))!P.call(a,t)&&t!==n&&b(a,t,{get:()=>e[t],enumerable:!(r=j(e,t))||r.enumerable});return a};var K=a=>_(b({},"__esModule",{value:!0}),a);var L={};V(L,{h:()=>m});module.exports=K(L);var i=class{jsonSchema={};get inferred(){return null}schema=this;_coerce=!1;coerce(){return this._coerce=!0,this}optional(){return new u(this)}enum(e){return new O(this,e)}array(){return new k(this)}instanceOf(e){return new x(this,e)}};function E(a,e){return typeof e=="string"&&a==="string"||typeof e=="number"&&a==="number"&&!Number.isNaN(e)||typeof e=="boolean"&&a==="boolean"}var S=class a extends i{type="string";_validateEmail=!1;_validatePhone=!1;_minLength;_maxLength;constructor(){super(),this.jsonSchema={type:"string"}}primitive(){return this.type}minLength(e){let n=new a;return Object.assign(n,this),n._minLength=e,n.jsonSchema={...this.jsonSchema,minLength:e},n}maxLength(e){let n=new a;return Object.assign(n,this),n._maxLength=e,n.jsonSchema={...this.jsonSchema,maxLength:e},n}email(){let e=new a;return e._validateEmail=!0,e.jsonSchema={...this.jsonSchema,format:"email"},e}phone(){let e=new a;return e._validatePhone=!0,e.jsonSchema={...this.jsonSchema,format:"phone"},e}"~standard"={version:1,vendor:"h-schema",validate:e=>(this._coerce&&typeof e!="string"&&(e=String(e)),typeof e!="string"?{issues:[{message:"Expected string, received "+typeof e}]}:this._minLength!==void 0&&e.length<this._minLength?{issues:[{message:`String shorter than ${this._minLength}`}]}:this._maxLength!==void 0&&e.length>this._maxLength?{issues:[{message:`String longer than ${this._maxLength}`}]}:this._validateEmail&&!this._isValidEmail(e)?{issues:[{message:"Invalid email format"}]}:this._validatePhone&&!this._isValidPhone(e)?{issues:[{message:"Invalid phone number format"}]}:{value:e}),types:{input:{},output:{}}};_isValidEmail(e){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}_isValidPhone(e){return/^\+?[0-9]{7,15}$/.test(e)}},p=class a extends i{type="number";_min;_max;constructor(){super(),this.jsonSchema={type:"number"}}primitive(){return this.type}min(e){let n=new a;return Object.assign(n,this),n._min=e,n.jsonSchema={...this.jsonSchema,minimum:e},n}max(e){let n=new a;return Object.assign(n,this),n._max=e,n.jsonSchema={...this.jsonSchema,maximum:e},n}"~standard"={version:1,vendor:"h-schema",validate:e=>{if(this._coerce&&typeof e!="number"){let n=Number(e);Number.isNaN(n)||(e=n)}return typeof e!="number"||Number.isNaN(e)?{issues:[{message:"Expected number, received "+typeof e}]}:this._min!==void 0&&e<this._min?{issues:[{message:`Number less than ${this._min}`}]}:this._max!==void 0&&e>this._max?{issues:[{message:`Number greater than ${this._max}`}]}:{value:e}},types:{input:{},output:{}}}},l=class extends i{type="boolean";constructor(){super(),this.jsonSchema={type:"boolean"}}primitive(){return this.type}"~standard"={version:1,vendor:"h-schema",validate:e=>(this._coerce&&typeof e!="boolean"&&(e==="true"||e===1||e==="1"?e=!0:(e==="false"||e===0||e==="0")&&(e=!1)),typeof e!="boolean"?{issues:[{message:"Expected boolean, received "+typeof e}]}:{value:e}),types:{input:{},output:{}}}},w=class extends i{type="any";"~standard"={version:1,vendor:"h-schema",validate:e=>({value:e}),types:{input:{},output:{}}}},g=class extends i{value;constructor(e){super(),this.value=e,this.jsonSchema={const:e,type:typeof e}}"~standard"={version:1,vendor:"h-schema",validate:e=>e!==this.value?{issues:[{message:`Expected literal value ${this.value}, received ${e}`}]}:{value:e},types:{input:{},output:{}}}},u=class extends i{innerSchema;constructor(e){super(),this.innerSchema=e,this.jsonSchema={...e.jsonSchema}}"~standard"={version:1,vendor:"h-schema",validate:async e=>e==null?{value:void 0}:await this.innerSchema["~standard"].validate(e),types:{input:{},output:{}}}},v=class extends i{type="null";constructor(){super(),this.jsonSchema={type:"null"}}"~standard"={version:1,vendor:"h-schema",validate:e=>e!==null?{issues:[{message:`Expected null, received ${e===void 0?"undefined":typeof e}`}]}:{value:null},types:{input:{},output:{}}}},I=class extends i{schemas;constructor(...e){super(),this.schemas=e,this.jsonSchema={anyOf:e.map(n=>n.jsonSchema)}}"~standard"={version:1,vendor:"h-schema",validate:async e=>{let n=[];for(let r of this.schemas){let t=await r["~standard"].validate(e);if(!("issues"in t))return{value:t.value};n.push(...t.issues)}return{issues:n}},types:{input:{},output:{}}}},O=class extends i{innerSchema;values;constructor(e,n){super(),this.innerSchema=e,this.values=n,this.jsonSchema={...e.jsonSchema,enum:n}}"~standard"={version:1,vendor:"h-schema",validate:async e=>{let n=await this.innerSchema["~standard"].validate(e);return"issues"in n?n:this.values.includes(n.value)?{value:n.value}:{issues:[{message:`Invalid enum value. Expected one of: ${this.values.join(", ")}`}]}},types:{input:{},output:{}}}},k=class extends i{innerSchema;constructor(e){super(),this.innerSchema=e,this.jsonSchema={type:"array",items:e.jsonSchema}}"~standard"={version:1,vendor:"h-schema",validate:async e=>{if(!Array.isArray(e))return{issues:[{message:"Expected array, received "+typeof e}]};let n=await Promise.all(e.map(async(t,s)=>{let o=await this.innerSchema["~standard"].validate(t);return"issues"in o?{index:s,issues:o.issues?.map(h=>({...h,path:h.path?[s,...h.path]:[s]}))}:{index:s,value:o.value}})),r=n.filter(t=>"issues"in t);return r.length>0?{issues:r.flatMap(t=>t.issues)}:{value:n.map(t=>"value"in t?t.value:null)}},types:{input:{},output:{}}}},x=class extends i{innerSchema;classConstructor;constructor(e,n){super(),this.innerSchema=e,this.classConstructor=n,this.jsonSchema={...e.jsonSchema,instanceOf:n.name}}"~standard"={version:1,vendor:"h-schema",validate:async e=>e instanceof this.classConstructor?await this.innerSchema["~standard"].validate(e):{issues:[{message:`Expected instance of ${this.classConstructor.name}`}]},types:{input:{},output:{}}}},y=class extends i{definition;constructor(e){super(),this.definition=e;let n={},r=[];for(let t in e){let s=e[t];s instanceof u||r.push(t),typeof s=="string"?n[t]={type:s}:s instanceof i?n[t]=s.jsonSchema:typeof s=="object"&&s!==null&&(n[t]={type:"object",properties:{}})}this.jsonSchema={type:"object",properties:n,required:r.length>0?r:void 0}}"~standard"={version:1,vendor:"h-schema",validate:async e=>{if(typeof e!="object"||e===null||Array.isArray(e))return{issues:[{message:"Expected object, received "+(e===null?"null":Array.isArray(e)?"array":typeof e)}]};let n=e,r={},t=[];for(let s in this.definition){let o=this.definition[s],h=o instanceof u;if(!(s in n)&&!h){t.push({message:`Missing required property: ${s}`,path:[s]});continue}if(s in n){if(typeof o=="string"&&o in["string","number","boolean"]){let c=o;E(c,n[s])?r[s]=n[s]:t.push({message:`Invalid type for property ${s}: expected ${c}`,path:[s]})}else if(o instanceof i){let c=await o["~standard"].validate(n[s]);"issues"in c?c.issues&&t.push(...c.issues.map(f=>({...f,path:f.path?[s,...f.path]:[s]}))):r[s]=c.value}}}return t.length>0?{issues:t}:{value:r}},types:{input:{},output:{}}}};function d(a){let e;if(a instanceof i)e=a;else if(typeof a=="string")if(a==="string")e=new S;else if(a==="number")e=new p;else if(a==="boolean")e=new l;else throw new Error("Invalid schema type provided to toStandard");else if(typeof a=="object"&&a!==null&&!Array.isArray(a))e=new y(a);else throw new Error("Invalid schema type provided to toStandard");let n={toJSONSchema:r=>r.jsonSchema};return{...e,inferred:null,"~standard":e["~standard"],jsonSchema:n.toJSONSchema(e),schema:e,optional:()=>new u(e),enum:e.enum.bind(e),array:e.array.bind(e),instanceOf:e.instanceOf.bind(e)}}var m={string:()=>new S,number:()=>new p,boolean:()=>new l,null:()=>new v,any:()=>new w,literal:a=>new g(a),object:a=>new y(a||{}),array:a=>d(a).array(),enum:a=>{let e=a[0],n;if(typeof e=="string")n=m.string();else if(typeof e=="number")n=m.number();else if(typeof e=="boolean")n=m.boolean();else throw new Error("Enum values must be primitives");return n.enum(a)},optional:a=>d(a).optional(),options:(...a)=>{let e=a.map(n=>d(n).schema);return new I(...e)},instanceOf:a=>m.object({}).instanceOf(a),email:()=>m.string().email(),phone:()=>m.string().phone(),toStandard:d};0&&(module.exports={h});
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
<p>
|
|
3
|
-
<strong>🚀 Hedystia Framework</strong>
|
|
4
|
-
</p>
|
|
5
|
-
|
|
6
|
-
<p>
|
|
7
|
-
<strong>Next-gen TypeScript framework for building type-safe APIs at lightspeed! ⚡</strong>
|
|
8
|
-
</p>
|
|
9
|
-
|
|
10
|
-
<p>
|
|
11
|
-
<a href="https://www.npmjs.com/package/hedystia"><img src="https://img.shields.io/npm/v/hedystia.svg?style=flat-square" alt="npm version"></a>
|
|
12
|
-
<a href="https://www.npmjs.com/package/hedystia"><img src="https://img.shields.io/npm/dm/hedystia.svg?style=flat-square" alt="npm downloads"></a>
|
|
13
|
-
<a href="LICENSE"><img src="https://img.shields.io/github/license/Hedystia/Framework.svg?style=flat-square" alt="license"></a>
|
|
14
|
-
<img src="https://img.shields.io/badge/Bun-powered-FFD43B?style=flat-square&logo=bun" alt="Bun powered">
|
|
15
|
-
</p>
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
## 🚨 Early Access Notice
|
|
19
|
-
> **Warning**
|
|
20
|
-
> Framework is in active development. Core features are stable but some advanced functionality still being implemented.
|
|
21
|
-
|
|
22
|
-
## 🌟 Superpowers
|
|
23
|
-
|
|
24
|
-
- 🌐 **Multi-runtime support** - Bun (default), Deno, Node.js, Vercel, Cloudflare Workers, Fastly Compute, Lambda, etc.
|
|
25
|
-
- 🔒 **End-to-end type safety** - From params to response, full TypeScript integration
|
|
26
|
-
- ⚡ **Bun-native performance** - Built for Bun runtime with native validation
|
|
27
|
-
- 🧩 **Client integration** - Auto-generated type-safe HTTP client
|
|
28
|
-
- 🛡️ **Validation built-in** - Zod integration for runtime safety
|
|
29
|
-
- 🔌 **Extensible architecture** - Middleware, hooks and macros system
|
|
30
|
-
- 📝 **Standard Schema** - Compatibility with the standard schema so you can use it with Zod, Arktype, etc.
|
|
31
|
-
|
|
32
|
-
## 🚀 Launch in 30 Seconds
|
|
33
|
-
|
|
34
|
-
1. Install with Bun:
|
|
35
|
-
```bash
|
|
36
|
-
bun add hedystia
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
2. Create your first API:
|
|
40
|
-
```typescript
|
|
41
|
-
import { Hedystia, h } from "hedystia";
|
|
42
|
-
|
|
43
|
-
const app = new Hedystia()
|
|
44
|
-
.get("/hello/:name", (ctx) => `Hello ${ctx.params.name}!`, {
|
|
45
|
-
params: h.object({ name: h.string() }),
|
|
46
|
-
response: h.string()
|
|
47
|
-
})
|
|
48
|
-
.listen(3000);
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
3. Generate client and consume API:
|
|
52
|
-
```typescript
|
|
53
|
-
import { createClient } from "@hedystia/client";
|
|
54
|
-
|
|
55
|
-
const client = createClient<typeof app>("http://localhost:3000");
|
|
56
|
-
|
|
57
|
-
// Fully typed request!
|
|
58
|
-
const { data } = await client.hello.name("World").get();
|
|
59
|
-
console.log(data); // "Hello World!"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## 💡 Why Developers Love Hedystia
|
|
63
|
-
|
|
64
|
-
### 🔄 Full-stack Type Safety
|
|
65
|
-
```typescript
|
|
66
|
-
// Server-side validation
|
|
67
|
-
.post("/users", (ctx) => {...}, {
|
|
68
|
-
body: h.object({
|
|
69
|
-
email: h.email(),
|
|
70
|
-
age: h.number()
|
|
71
|
-
})
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
// Client-side types
|
|
75
|
-
await client.users.post({
|
|
76
|
-
email: "user@example.com", // Autocompletes!
|
|
77
|
-
age: 25 // Type-checked
|
|
78
|
-
});
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### 📖 Swagger Integration
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import { swagger } from "@hedystia/swagger";
|
|
85
|
-
|
|
86
|
-
const swaggerPlugin = swagger({
|
|
87
|
-
title: "My API",
|
|
88
|
-
description: "An example API with Swagger",
|
|
89
|
-
version: "1.0.0",
|
|
90
|
-
tags: [
|
|
91
|
-
{ name: "users", description: "User operations" },
|
|
92
|
-
],
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
swaggerPlugin.captureRoutes(app);
|
|
96
|
-
|
|
97
|
-
app.use("/swagger", swaggerPlugin.plugin).listen(3000);
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### ⚡ Performance First
|
|
101
|
-
- Bun runtime optimized
|
|
102
|
-
- Faster by default
|
|
103
|
-
- Own type validation system
|
|
104
|
-
- Faster than Express
|
|
105
|
-
- Built-in response compression
|
|
106
|
-
|
|
107
|
-
### 🧩 Modern Feature Set
|
|
108
|
-
```typescript
|
|
109
|
-
// File uploads
|
|
110
|
-
.post("/upload", async (ctx) => {
|
|
111
|
-
const formData = await ctx.body; // FormData type
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
// Binary responses
|
|
115
|
-
.get("/pdf", () => new Blob([...]), {
|
|
116
|
-
response: h.instanceof(Blob)
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
// Nested routing
|
|
120
|
-
.group("/api/v1", (v1) => v1
|
|
121
|
-
.group("/users", (users) => users
|
|
122
|
-
.get("/:id", ...)
|
|
123
|
-
)
|
|
124
|
-
)
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## 🛠️ Development Roadmap
|
|
128
|
-
|
|
129
|
-
### Core Features
|
|
130
|
-
- ✅ HTTP Methods: GET, POST, PUT, PATCH, DELETE
|
|
131
|
-
- ✅ Response Types: JSON, Text, FormData, Blob, ArrayBuffer
|
|
132
|
-
- ✅ Router Groups & Middleware
|
|
133
|
-
- ✅ Type-safe Client Generation
|
|
134
|
-
- ✅ WebSocket Support
|
|
135
|
-
- ✅ Adapter System to work with other frameworks
|
|
136
|
-
|
|
137
|
-
### Advanced Capabilities
|
|
138
|
-
- ✅ Standard Schema Compatibility
|
|
139
|
-
- ✅ Hooks System (onRequest, onError, etc)
|
|
140
|
-
- ✅ Macro System for Auth/Rate Limiting
|
|
141
|
-
- ✅ OpenAPI - Swagger Integration
|
|
142
|
-
|
|
143
|
-
## 💼 Production Ready
|
|
144
|
-
```typescript
|
|
145
|
-
// Error handling
|
|
146
|
-
.onError((err) => {
|
|
147
|
-
return Response.json({
|
|
148
|
-
error: err.message
|
|
149
|
-
}, { status: 500 })
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
// Rate limiting macro
|
|
153
|
-
.macro({
|
|
154
|
-
rateLimit: () => ({
|
|
155
|
-
resolve: async (ctx) => {
|
|
156
|
-
// Implement your logic
|
|
157
|
-
}
|
|
158
|
-
})
|
|
159
|
-
})
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## 📜 License
|
|
163
|
-
MIT License © 2025 Hedystia
|
|
164
|
-
|
|
165
|
-
## 🗣️ Community
|
|
166
|
-
- [GitHub Issues](https://github.com/Hedystia/Framework/issues)
|
|
167
|
-
- [Discord Server](https://hedystia.com/support)
|
|
1
|
+
<div align="center">
|
|
2
|
+
<p>
|
|
3
|
+
<strong>🚀 Hedystia Framework</strong>
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
<strong>Next-gen TypeScript framework for building type-safe APIs at lightspeed! ⚡</strong>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p>
|
|
11
|
+
<a href="https://www.npmjs.com/package/hedystia"><img src="https://img.shields.io/npm/v/hedystia.svg?style=flat-square" alt="npm version"></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/hedystia"><img src="https://img.shields.io/npm/dm/hedystia.svg?style=flat-square" alt="npm downloads"></a>
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/Hedystia/Framework.svg?style=flat-square" alt="license"></a>
|
|
14
|
+
<img src="https://img.shields.io/badge/Bun-powered-FFD43B?style=flat-square&logo=bun" alt="Bun powered">
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
## 🚨 Early Access Notice
|
|
19
|
+
> **Warning**
|
|
20
|
+
> Framework is in active development. Core features are stable but some advanced functionality still being implemented.
|
|
21
|
+
|
|
22
|
+
## 🌟 Superpowers
|
|
23
|
+
|
|
24
|
+
- 🌐 **Multi-runtime support** - Bun (default), Deno, Node.js, Vercel, Cloudflare Workers, Fastly Compute, Lambda, etc.
|
|
25
|
+
- 🔒 **End-to-end type safety** - From params to response, full TypeScript integration
|
|
26
|
+
- ⚡ **Bun-native performance** - Built for Bun runtime with native validation
|
|
27
|
+
- 🧩 **Client integration** - Auto-generated type-safe HTTP client
|
|
28
|
+
- 🛡️ **Validation built-in** - Zod integration for runtime safety
|
|
29
|
+
- 🔌 **Extensible architecture** - Middleware, hooks and macros system
|
|
30
|
+
- 📝 **Standard Schema** - Compatibility with the standard schema so you can use it with Zod, Arktype, etc.
|
|
31
|
+
|
|
32
|
+
## 🚀 Launch in 30 Seconds
|
|
33
|
+
|
|
34
|
+
1. Install with Bun:
|
|
35
|
+
```bash
|
|
36
|
+
bun add hedystia
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. Create your first API:
|
|
40
|
+
```typescript
|
|
41
|
+
import { Hedystia, h } from "hedystia";
|
|
42
|
+
|
|
43
|
+
const app = new Hedystia()
|
|
44
|
+
.get("/hello/:name", (ctx) => `Hello ${ctx.params.name}!`, {
|
|
45
|
+
params: h.object({ name: h.string() }),
|
|
46
|
+
response: h.string()
|
|
47
|
+
})
|
|
48
|
+
.listen(3000);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
3. Generate client and consume API:
|
|
52
|
+
```typescript
|
|
53
|
+
import { createClient } from "@hedystia/client";
|
|
54
|
+
|
|
55
|
+
const client = createClient<typeof app>("http://localhost:3000");
|
|
56
|
+
|
|
57
|
+
// Fully typed request!
|
|
58
|
+
const { data } = await client.hello.name("World").get();
|
|
59
|
+
console.log(data); // "Hello World!"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 💡 Why Developers Love Hedystia
|
|
63
|
+
|
|
64
|
+
### 🔄 Full-stack Type Safety
|
|
65
|
+
```typescript
|
|
66
|
+
// Server-side validation
|
|
67
|
+
.post("/users", (ctx) => {...}, {
|
|
68
|
+
body: h.object({
|
|
69
|
+
email: h.email(),
|
|
70
|
+
age: h.number()
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Client-side types
|
|
75
|
+
await client.users.post({
|
|
76
|
+
email: "user@example.com", // Autocompletes!
|
|
77
|
+
age: 25 // Type-checked
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 📖 Swagger Integration
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { swagger } from "@hedystia/swagger";
|
|
85
|
+
|
|
86
|
+
const swaggerPlugin = swagger({
|
|
87
|
+
title: "My API",
|
|
88
|
+
description: "An example API with Swagger",
|
|
89
|
+
version: "1.0.0",
|
|
90
|
+
tags: [
|
|
91
|
+
{ name: "users", description: "User operations" },
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
swaggerPlugin.captureRoutes(app);
|
|
96
|
+
|
|
97
|
+
app.use("/swagger", swaggerPlugin.plugin).listen(3000);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### ⚡ Performance First
|
|
101
|
+
- Bun runtime optimized
|
|
102
|
+
- Faster by default
|
|
103
|
+
- Own type validation system
|
|
104
|
+
- Faster than Express
|
|
105
|
+
- Built-in response compression
|
|
106
|
+
|
|
107
|
+
### 🧩 Modern Feature Set
|
|
108
|
+
```typescript
|
|
109
|
+
// File uploads
|
|
110
|
+
.post("/upload", async (ctx) => {
|
|
111
|
+
const formData = await ctx.body; // FormData type
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// Binary responses
|
|
115
|
+
.get("/pdf", () => new Blob([...]), {
|
|
116
|
+
response: h.instanceof(Blob)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// Nested routing
|
|
120
|
+
.group("/api/v1", (v1) => v1
|
|
121
|
+
.group("/users", (users) => users
|
|
122
|
+
.get("/:id", ...)
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 🛠️ Development Roadmap
|
|
128
|
+
|
|
129
|
+
### Core Features
|
|
130
|
+
- ✅ HTTP Methods: GET, POST, PUT, PATCH, DELETE
|
|
131
|
+
- ✅ Response Types: JSON, Text, FormData, Blob, ArrayBuffer
|
|
132
|
+
- ✅ Router Groups & Middleware
|
|
133
|
+
- ✅ Type-safe Client Generation
|
|
134
|
+
- ✅ WebSocket Support
|
|
135
|
+
- ✅ Adapter System to work with other frameworks
|
|
136
|
+
|
|
137
|
+
### Advanced Capabilities
|
|
138
|
+
- ✅ Standard Schema Compatibility
|
|
139
|
+
- ✅ Hooks System (onRequest, onError, etc)
|
|
140
|
+
- ✅ Macro System for Auth/Rate Limiting
|
|
141
|
+
- ✅ OpenAPI - Swagger Integration
|
|
142
|
+
|
|
143
|
+
## 💼 Production Ready
|
|
144
|
+
```typescript
|
|
145
|
+
// Error handling
|
|
146
|
+
.onError((err) => {
|
|
147
|
+
return Response.json({
|
|
148
|
+
error: err.message
|
|
149
|
+
}, { status: 500 })
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// Rate limiting macro
|
|
153
|
+
.macro({
|
|
154
|
+
rateLimit: () => ({
|
|
155
|
+
resolve: async (ctx) => {
|
|
156
|
+
// Implement your logic
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 📜 License
|
|
163
|
+
MIT License © 2025 Hedystia
|
|
164
|
+
|
|
165
|
+
## 🗣️ Community
|
|
166
|
+
- [GitHub Issues](https://github.com/Hedystia/Framework/issues)
|
|
167
|
+
- [Discord Server](https://hedystia.com/support)
|