@asterflow/response 1.0.1

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 ADDED
@@ -0,0 +1,214 @@
1
+ <div align="center">
2
+
3
+ # @asterflow/response
4
+
5
+ ![license-info](https://img.shields.io/github/license/Ashu11-A/AsterFlow?style=for-the-badge&colorA=302D41&colorB=f9e2af&logoColor=f9e2af)
6
+ ![stars-info](https://img.shields.io/github/stars/Ashu11-A/AsterFlow?colorA=302D41&colorB=f9e2af&style=for-the-badge)
7
+
8
+ ![last-commit](https://img.shields.io/github/last-commit/Ashu11-A/AsterFlow?style=for-the-badge&colorA=302D41&colorB=b4befe)
9
+ ![commit-activity](https://img.shields.io/github/commit-activity/y/Ashu11-A/AsterFlow?style=for-the-badge&colorA=302D41&colorB=f9e2af)
10
+ ![code-size](https://img.shields.io/github/languages/code-size/Ashu11-A/AsterFlow?style=for-the-badge&colorA=302D41&colorB=90dceb)
11
+
12
+ ![top-language](https://img.shields.io/github/languages/top/Ashu11-A/AsterFlow?style=for-the-badge&colorA=302D41&colorB=90dceb)
13
+ ![bundle-size](https://img.shields.io/bundlejs/size/@asterflow/response?style=for-the-badge&colorA=302D41&colorB=3ac97b)
14
+
15
+ </div>
16
+
17
+ > Unified HTTP response adapter system for AsterFlow applications.
18
+
19
+ ## 📦 Installation
20
+
21
+ ```bash
22
+ npm install @asterflow/response
23
+ # or
24
+ bun install @asterflow/response
25
+ ```
26
+
27
+ ## 💡 About
28
+
29
+ @asterflow/response provides a type-safe, unified response system for AsterFlow applications. It standardizes HTTP response handling across different runtimes while maintaining full type safety and providing convenient helper methods for common HTTP status codes.
30
+
31
+ ## ✨ Features
32
+
33
+ - **Complete Type Safety:** Full TypeScript support with type inference for responses, status codes, and body types
34
+ - **Status Code Helpers:** Built-in methods for common HTTP status codes (200, 201, 400, 404, etc.)
35
+ - **Header Management:** Type-safe header manipulation with method chaining
36
+ - **Cookie Support:** Integrated cookie management system
37
+ - **Content Type Detection:** Automatic content type detection and JSON serialization
38
+ - **Multi-Runtime Support:** Compatible with standard Response and Node.js ServerResponse
39
+ - **Immutable Design:** Response objects are immutable, promoting safer code patterns
40
+ - **Method Chaining:** Fluent API for building complex responses
41
+
42
+ ## 🚀 Usage
43
+
44
+ ### Basic Response
45
+
46
+ ```typescript
47
+ import { Response } from '@asterflow/response'
48
+
49
+ // Simple text response
50
+ const response = new Response()
51
+ .success({ message: 'Hello World!' })
52
+
53
+ // With status code
54
+ const response = new Response()
55
+ .status(201)
56
+ .send({ id: 1, name: 'User' })
57
+ ```
58
+
59
+ ### Status Code Helpers
60
+
61
+ ```typescript
62
+ import { Response } from '@asterflow/response'
63
+
64
+ // Success responses
65
+ const success = new Response().success({ data: 'Success!' })
66
+ const created = new Response().created({ id: 1 })
67
+ const noContent = new Response().noContent()
68
+
69
+ // Error responses
70
+ const badRequest = new Response().badRequest({ error: 'Invalid input' })
71
+ const unauthorized = new Response().unauthorized({ error: 'Not authenticated' })
72
+ const forbidden = new Response().forbidden({ error: 'Access denied' })
73
+ const notFound = new Response().notFound({ error: 'Resource not found' })
74
+ const zodError = new Response().zodError({ errors: ['Validation failed'] })
75
+ ```
76
+
77
+ ### Headers and Cookies
78
+
79
+ ```typescript
80
+ import { Response } from '@asterflow/response'
81
+
82
+ const response = new Response()
83
+ .success({ message: 'Hello!' })
84
+ .setHeader('X-Custom-Header', 'custom-value')
85
+ .setHeader('Cache-Control', 'no-cache')
86
+ .setCookie('session', 'abc123')
87
+ .setCookie('theme', 'dark')
88
+
89
+ // Headers and cookies are fully typed
90
+ console.log(response.header) // Map with typed entries
91
+ console.log(response.cookies) // Map with typed entries
92
+ ```
93
+
94
+ ### JSON Responses
95
+
96
+ ```typescript
97
+ import { Response } from '@asterflow/response'
98
+
99
+ // Automatic JSON serialization
100
+ const jsonResponse = new Response()
101
+ .json({
102
+ users: [
103
+ { id: 1, name: 'John' },
104
+ { id: 2, name: 'Jane' }
105
+ ]
106
+ })
107
+
108
+ // Content-Type automatically set to application/json
109
+ ```
110
+
111
+ ### Integration with Different Runtimes
112
+
113
+ #### Standard Web API
114
+
115
+ ```typescript
116
+ import { Response } from '@asterflow/response'
117
+
118
+ const response = new Response()
119
+ .success({ message: 'Hello World!' })
120
+
121
+ // Convert to standard Response
122
+ const webResponse = response.toResponse()
123
+ ```
124
+
125
+ #### Node.js HTTP Server
126
+
127
+ ```typescript
128
+ import { Response } from '@asterflow/response'
129
+ import { createServer } from 'http'
130
+
131
+ createServer((req, res) => {
132
+ const response = new Response()
133
+ .success({ message: 'Hello from Node.js!' })
134
+
135
+ // Convert to ServerResponse
136
+ response.toServerResponse(res)
137
+ })
138
+ ```
139
+
140
+ ### Advanced Type Safety
141
+
142
+ ```typescript
143
+ import { Response } from '@asterflow/response'
144
+
145
+ // Define custom response types
146
+ type MyResponders = {
147
+ 200: { message: string; data: unknown }
148
+ 201: { id: number; message: string }
149
+ 400: { error: string; details?: string[] }
150
+ 404: { error: string }
151
+ }
152
+
153
+ const response = new Response<MyResponders>()
154
+ .success({ message: 'Success!', data: { id: 1 } }) // Fully typed
155
+
156
+ // TypeScript will enforce the correct shape for each status code
157
+ ```
158
+
159
+ ### Method Chaining
160
+
161
+ ```typescript
162
+ import { Response } from '@asterflow/response'
163
+
164
+ const response = new Response()
165
+ .status(201)
166
+ .setHeader('Location', '/users/123')
167
+ .setHeader('X-Request-ID', 'req-123')
168
+ .setCookie('last-action', 'create-user')
169
+ .json({
170
+ id: 123,
171
+ message: 'User created successfully'
172
+ })
173
+ ```
174
+
175
+ ## 🔧 API Reference
176
+
177
+ ### Core Methods
178
+
179
+ - `status(code)` - Set HTTP status code
180
+ - `getStatus()` - Get current status code
181
+ - `send(data)` - Send response with data
182
+ - `json(data)` - Send JSON response with proper Content-Type
183
+
184
+ ### Status Code Helpers
185
+
186
+ - `success(data)` - 200 OK
187
+ - `created(data)` - 201 Created
188
+ - `noContent(data)` - 204 No Content
189
+ - `badRequest(data)` - 400 Bad Request
190
+ - `unauthorized(data)` - 401 Unauthorized
191
+ - `forbidden(data)` - 403 Forbidden
192
+ - `notFound(data)` - 404 Not Found
193
+ - `zodError(data)` - 422 Unprocessable Entity
194
+
195
+ ### Header and Cookie Management
196
+
197
+ - `setHeader(name, value)` - Add/update header
198
+ - `setCookie(name, value)` - Add/update cookie
199
+
200
+ ### Runtime Conversion
201
+
202
+ - `toResponse()` - Convert to standard Web API Response
203
+ - `toServerResponse(serverRes)` - Write to Node.js ServerResponse
204
+
205
+ ## 🔗 Related Packages
206
+
207
+ - [@asterflow/core](https://www.npmjs.com/package/@asterflow/core) - Core framework
208
+ - [@asterflow/router](https://www.npmjs.com/package/@asterflow/router) - Type-safe routing system
209
+ - [@asterflow/adapter](https://www.npmjs.com/package/@asterflow/adapter) - HTTP adapters for different runtimes
210
+ - [@asterflow/request](https://www.npmjs.com/package/@asterflow/request) - Unified HTTP request system
211
+
212
+ ## 📄 License
213
+
214
+ MIT - See [LICENSE](https://github.com/Ashu11-A/AsterFlow/blob/main/LICENSE) for more details.
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var r = Object.defineProperty;
3
+ var d = Object.getOwnPropertyDescriptor;
4
+ var p = Object.getOwnPropertyNames;
5
+ var c = Object.prototype.hasOwnProperty;
6
+ var h = (n, e) => {
7
+ for (var t in e)
8
+ r(n, t, { get: e[t], enumerable: !0 });
9
+ }, u = (n, e, t, s) => {
10
+ if (e && typeof e == "object" || typeof e == "function")
11
+ for (let o of p(e))
12
+ !c.call(n, o) && o !== t && r(n, o, { get: () => e[o], enumerable: !(s = d(e, o)) || s.enumerable });
13
+ return n;
14
+ };
15
+ var M = (n) => u(r({}, "__esModule", { value: !0 }), n);
16
+
17
+ // packages/response/src/index.ts
18
+ var y = {};
19
+ h(y, {
20
+ Response: () => i
21
+ });
22
+ module.exports = M(y);
23
+
24
+ // packages/response/src/controllers/Response.ts
25
+ var i = class n {
26
+ _status;
27
+ body;
28
+ header;
29
+ cookies;
30
+ constructor(e) {
31
+ this._status = e?.code ?? 200, this.body = e?.data, this.header = e?.header ?? /* @__PURE__ */ new Map(), this.cookies = e?.cookies ?? /* @__PURE__ */ new Map();
32
+ }
33
+ clone(e) {
34
+ return new n({
35
+ code: e.code !== void 0 ? e.code : this._status,
36
+ data: e.data !== void 0 ? e.data : this.body,
37
+ header: e.header !== void 0 ? e.header : this.header,
38
+ cookies: e.cookies !== void 0 ? e.cookies : this.cookies
39
+ });
40
+ }
41
+ // --- Core Methods ---
42
+ status(e) {
43
+ return this.clone({ code: e });
44
+ }
45
+ getStatus() {
46
+ return this._status;
47
+ }
48
+ code(e) {
49
+ return this.status(e);
50
+ }
51
+ send(e) {
52
+ return this.clone({ data: e });
53
+ }
54
+ json(e) {
55
+ let t = new Map(this.header);
56
+ return t.set("Content-Type", "application/json"), this.clone({ data: e, header: t });
57
+ }
58
+ // --- Response Helpers ---
59
+ success(e) {
60
+ return this.clone({ code: 200, data: e });
61
+ }
62
+ created(e) {
63
+ return this.clone({ code: 201, data: e });
64
+ }
65
+ noContent(e) {
66
+ return this.clone({ code: 204, data: e });
67
+ }
68
+ badRequest(e) {
69
+ return this.clone({ code: 400, data: e });
70
+ }
71
+ zodError(e) {
72
+ return this.clone({ code: 422, data: e });
73
+ }
74
+ unauthorized(e) {
75
+ return this.clone({ code: 401, data: e });
76
+ }
77
+ forbidden(e) {
78
+ return this.clone({ code: 403, data: e });
79
+ }
80
+ notFound(e) {
81
+ return this.clone({ code: 404, data: e });
82
+ }
83
+ setHeader(e, t) {
84
+ let s = new Map(this.header);
85
+ return s.set(e, t), this.clone({ header: s });
86
+ }
87
+ setCookie(e, t) {
88
+ let s = new Map(this.cookies);
89
+ return s.set(e, t), this.clone({ cookies: s });
90
+ }
91
+ toResponse() {
92
+ let e = new Headers();
93
+ e.set("Content-Type", "text/plain");
94
+ for (let [s, o] of this.header) e.set(s, o);
95
+ (typeof this.body == "object" || Array.isArray(this.body)) && e.set("Content-Type", "application/json");
96
+ for (let [s, o] of this.cookies) e.append("Set-Cookie", `${s}=${o}`);
97
+ let t = e.get("Content-Type") === "application/json" ? JSON.stringify(this.body) : String(this.body);
98
+ return new globalThis.Response(t, {
99
+ status: this._status,
100
+ headers: e
101
+ });
102
+ }
103
+ toServerResponse(e) {
104
+ let t = new Headers();
105
+ t.set("Content-Type", "text/plain");
106
+ for (let [o, a] of this.header) t.set(o, a);
107
+ (typeof this.body == "object" || Array.isArray(this.body)) && t.set("Content-Type", "application/json");
108
+ for (let [o, a] of this.cookies) t.append("Set-Cookie", `${o}=${a}`);
109
+ let s = t.get("Content-Type") === "application/json" ? JSON.stringify(this.body) : String(this.body);
110
+ e.writeHead(this._status, Object.fromEntries(t)), e.end(s);
111
+ }
112
+ };
113
+ // Annotate the CommonJS export names for ESM import in node:
114
+ 0 && (module.exports = {
115
+ Response
116
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,92 @@
1
+ // packages/response/src/controllers/Response.ts
2
+ var a = class r {
3
+ _status;
4
+ body;
5
+ header;
6
+ cookies;
7
+ constructor(e) {
8
+ this._status = e?.code ?? 200, this.body = e?.data, this.header = e?.header ?? /* @__PURE__ */ new Map(), this.cookies = e?.cookies ?? /* @__PURE__ */ new Map();
9
+ }
10
+ clone(e) {
11
+ return new r({
12
+ code: e.code !== void 0 ? e.code : this._status,
13
+ data: e.data !== void 0 ? e.data : this.body,
14
+ header: e.header !== void 0 ? e.header : this.header,
15
+ cookies: e.cookies !== void 0 ? e.cookies : this.cookies
16
+ });
17
+ }
18
+ // --- Core Methods ---
19
+ status(e) {
20
+ return this.clone({ code: e });
21
+ }
22
+ getStatus() {
23
+ return this._status;
24
+ }
25
+ code(e) {
26
+ return this.status(e);
27
+ }
28
+ send(e) {
29
+ return this.clone({ data: e });
30
+ }
31
+ json(e) {
32
+ let t = new Map(this.header);
33
+ return t.set("Content-Type", "application/json"), this.clone({ data: e, header: t });
34
+ }
35
+ // --- Response Helpers ---
36
+ success(e) {
37
+ return this.clone({ code: 200, data: e });
38
+ }
39
+ created(e) {
40
+ return this.clone({ code: 201, data: e });
41
+ }
42
+ noContent(e) {
43
+ return this.clone({ code: 204, data: e });
44
+ }
45
+ badRequest(e) {
46
+ return this.clone({ code: 400, data: e });
47
+ }
48
+ zodError(e) {
49
+ return this.clone({ code: 422, data: e });
50
+ }
51
+ unauthorized(e) {
52
+ return this.clone({ code: 401, data: e });
53
+ }
54
+ forbidden(e) {
55
+ return this.clone({ code: 403, data: e });
56
+ }
57
+ notFound(e) {
58
+ return this.clone({ code: 404, data: e });
59
+ }
60
+ setHeader(e, t) {
61
+ let s = new Map(this.header);
62
+ return s.set(e, t), this.clone({ header: s });
63
+ }
64
+ setCookie(e, t) {
65
+ let s = new Map(this.cookies);
66
+ return s.set(e, t), this.clone({ cookies: s });
67
+ }
68
+ toResponse() {
69
+ let e = new Headers();
70
+ e.set("Content-Type", "text/plain");
71
+ for (let [s, o] of this.header) e.set(s, o);
72
+ (typeof this.body == "object" || Array.isArray(this.body)) && e.set("Content-Type", "application/json");
73
+ for (let [s, o] of this.cookies) e.append("Set-Cookie", `${s}=${o}`);
74
+ let t = e.get("Content-Type") === "application/json" ? JSON.stringify(this.body) : String(this.body);
75
+ return new globalThis.Response(t, {
76
+ status: this._status,
77
+ headers: e
78
+ });
79
+ }
80
+ toServerResponse(e) {
81
+ let t = new Headers();
82
+ t.set("Content-Type", "text/plain");
83
+ for (let [o, n] of this.header) t.set(o, n);
84
+ (typeof this.body == "object" || Array.isArray(this.body)) && t.set("Content-Type", "application/json");
85
+ for (let [o, n] of this.cookies) t.append("Set-Cookie", `${o}=${n}`);
86
+ let s = t.get("Content-Type") === "application/json" ? JSON.stringify(this.body) : String(this.body);
87
+ e.writeHead(this._status, Object.fromEntries(t)), e.end(s);
88
+ }
89
+ };
90
+ export {
91
+ a as Response
92
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,37 @@
1
+ import type { BodyMap, Responders, ResponseOptions } from '../types/response';
2
+ import { ServerResponse } from 'http';
3
+ export declare class Response<Responder extends Responders = Responders, BM extends BodyMap<Responder> = BodyMap<Responder>, Status extends keyof BM = keyof BM, Header extends Map<string, string> = Map<string, string>, Cookies extends Map<string, string> = Map<string, string>> {
4
+ protected readonly _status: Status;
5
+ readonly body?: BM[Status];
6
+ readonly header: Header;
7
+ readonly cookies: Cookies;
8
+ constructor(options?: ResponseOptions<Responder, BM, Status, Header, Cookies>);
9
+ protected clone<NewHeader extends Map<string, string> = Header, NewCookies extends Map<string, string> = Cookies>(overrides: {
10
+ data?: BM[Status];
11
+ header?: NewHeader;
12
+ cookies?: NewCookies;
13
+ }): Response<Responder, BM, Status, NewHeader, NewCookies>;
14
+ protected clone<NewStatus extends keyof BM, NewCookies extends Map<string, string> = Cookies>(overrides: {
15
+ code: NewStatus;
16
+ data?: BM[NewStatus];
17
+ header?: Header;
18
+ cookies?: NewCookies;
19
+ }): Response<Responder, BM, NewStatus, Header, NewCookies>;
20
+ status<NS extends keyof BM>(code: NS): Response<Responder, BM, NS, Header, Cookies>;
21
+ getStatus(): Status;
22
+ code<NS extends keyof BM>(code: NS): Response<Responder, BM, NS, Header, Cookies>;
23
+ send(data: BM[Status]): Response<Responder, BM, Status, Header, Cookies>;
24
+ json(data: BM[Status]): Response<Responder, BM, Status, Header & Map<"Content-Type", "application/json">, Cookies>;
25
+ success(data: BM[200]): Response<Responder, BM, 200, Header, Cookies>;
26
+ created(data: BM[201]): Response<Responder, BM, 201, Header, Cookies>;
27
+ noContent(data: BM[204]): Response<Responder, BM, 204, Header, Cookies>;
28
+ badRequest(data: BM[400]): Response<Responder, BM, 400, Header, Cookies>;
29
+ zodError(data: BM[422]): Response<Responder, BM, 422, Header, Cookies>;
30
+ unauthorized(data: BM[401]): Response<Responder, BM, 401, Header, Cookies>;
31
+ forbidden(data: BM[403]): Response<Responder, BM, 403, Header, Cookies>;
32
+ notFound(data: BM[404]): Response<Responder, BM, 404, Header, Cookies>;
33
+ setHeader<Name extends string, Value extends string>(name: Name, value: Value): Response<Responder, BM, Status, Header & Map<Name, Value>, Cookies>;
34
+ setCookie<Name extends string, Value extends string>(name: Name, value: Value): Response<Responder, BM, Status, Header, Cookies & Map<Name, Value>>;
35
+ toResponse(): globalThis.Response;
36
+ toServerResponse(output: ServerResponse): void;
37
+ }
@@ -0,0 +1,2 @@
1
+ export * from './types/response';
2
+ export * from './controllers/Response';
@@ -0,0 +1,12 @@
1
+ export type Responders = {
2
+ [x in number]: unknown;
3
+ };
4
+ export type BodyMap<Responder extends Responders> = {
5
+ [S in keyof Responder]: Responder[S];
6
+ };
7
+ export type ResponseOptions<Responder extends Responders, BM extends BodyMap<Responder>, Status extends keyof BM, Header extends Map<string, string>, Cookies extends Map<string, string>> = {
8
+ data?: BM[Status];
9
+ code?: Status;
10
+ header?: Header;
11
+ cookies?: Cookies;
12
+ };
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@asterflow/response",
3
+ "version": "1.0.1",
4
+ "main": "dist/cjs/index.cjs",
5
+ "module": "dist/mjs/index.js",
6
+ "types": "dist/types/index.d.ts",
7
+ "typings": "dist/types/index.d.ts",
8
+ "type": "module",
9
+ "license": "MIT",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/types/index.d.ts",
13
+ "import": "./dist/mjs/index.js",
14
+ "require": "./dist/cjs/index.cjs"
15
+ }
16
+ },
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "peerDependencies": {
21
+ "typescript": "^5.8.3"
22
+ }
23
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": [
4
+ "ESNext"
5
+ ],
6
+ "target": "ESNext",
7
+ "module": "ESNext",
8
+ "moduleDetection": "force",
9
+ "jsx": "react-jsx",
10
+ "allowJs": true,
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "noEmit": true,
15
+ "strict": true,
16
+ "skipLibCheck": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "noUncheckedIndexedAccess": true,
19
+ "noUnusedLocals": false,
20
+ "noUnusedParameters": false,
21
+ "noPropertyAccessFromIndexSignature": false
22
+ },
23
+ "include": [
24
+ "dist"
25
+ ]
26
+ }