UNPKG

8.41 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _GenericError = require('../error/GenericError');
8
9var _GenericError2 = _interopRequireDefault(_GenericError);
10
11function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
13// @server-side class Response {__CLEAR__}\nexports.default = Response;
14
15/**
16 * Wrapper for the ExpressJS response, exposing only the necessary minimum.
17 */
18class Response {
19 static get $dependencies() {
20 return [];
21 }
22
23 /**
24 * Initializes the response.
25 */
26 constructor() {
27 /**
28 * The ExpressJS response object, or {@code null} if running at the
29 * client side.
30 *
31 * @type {?Express.Response}
32 */
33 this._response = null;
34
35 /**
36 * It is flag for sent response for request.
37 *
38 * @type {boolean}
39 */
40 this._isSent = false;
41
42 /**
43 * HTTP Status code.
44 *
45 * @type {number}
46 */
47 this._status = 500;
48
49 /**
50 * The content of response.
51 *
52 * @type {string}
53 */
54 this._content = '';
55
56 /**
57 * The rendered page state.
58 *
59 * @type {Object<string, *>}
60 */
61 this._pageState = {};
62
63 /**
64 * Internal cookie storage for Set-Cookie header.
65 *
66 * @type {Map<string, {
67 * value: string,
68 * options: {domain: string=, expires: (number|string)=}
69 * }>}
70 */
71 this._internalCookieStorage = new Map();
72
73 /**
74 * Transform function for cookie value.
75 *
76 * @type {{encode: function, decode: function}}
77 */
78 this._cookieTransformFunction = {
79 encode: value => value,
80 decode: value => value
81 };
82 }
83
84 /**
85 * Initializes this response wrapper with the provided ExpressJS response
86 * object.
87 *
88 * @param {?Express.Response} response The ExpressJS response, or
89 * {@code null} if the code is running at the client side.
90 * @param {{
91 * encode: function(string): string=,
92 * decode: function(string): string
93 * }=} cookieTransformFunction
94 * @return {ima.router.Response} This response.
95 */
96 init(response, cookieTransformFunction = {}) {
97 this._cookieTransformFunction = Object.assign(this._cookieTransformFunction, cookieTransformFunction);
98 this._response = response;
99 this._isSent = false;
100 this._status = 500;
101 this._content = '';
102 this._pageState = {};
103 this._internalCookieStorage = new Map();
104
105 return this;
106 }
107
108 /**
109 * Redirects the client to the specified location, with the specified
110 * redirect HTTP response code.
111 *
112 * For full list of HTTP response status codes see
113 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
114 *
115 * Use this method only at the server side.
116 *
117 * @param {string} url The URL to which the client should be redirected.
118 * @param {number=} [status=302] The HTTP status code to send to the
119 * client.
120 * @return {Response} This response.
121 */
122 redirect(url, status = 302) {
123 if ($Debug) {
124 if (this._isSent === true) {
125 let params = this.getResponseParams();
126 params.url = url;
127
128 throw new _GenericError2.default('ima.router.Response:redirect The response has already ' + 'been sent. Check your workflow.', params);
129 }
130 }
131
132 this._isSent = true;
133 this._status = status;
134 this._setCookieHeaders();
135 this._response.redirect(status, url);
136
137 return this;
138 }
139
140 /**
141 * Sets the HTTP status code that will be sent to the client when the
142 * response is sent.
143 *
144 * For full list of available response codes see
145 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
146 *
147 * Use this method only at the server side.
148 *
149 * @param {number} httpStatus HTTP response status code to send to the
150 * client.
151 * @return {Response} This response.
152 */
153 status(httpStatus) {
154 if ($Debug) {
155 if (this._isSent === true) {
156 let params = this.getResponseParams();
157
158 throw new _GenericError2.default('ima.router.Response:status The response has already ' + 'been sent. Check your workflow.', params);
159 }
160 }
161
162 this._status = httpStatus;
163 this._response.status(httpStatus);
164
165 return this;
166 }
167
168 /**
169 * Sends the response to the client with the provided content. Use this
170 * method only at the server side.
171 *
172 * @param {string} content The response body.
173 * @return {Response} This response.
174 */
175 send(content) {
176 if ($Debug) {
177 if (this._isSent === true) {
178 let params = this.getResponseParams();
179 params.content = content;
180
181 throw new _GenericError2.default('ima.router.Response:send The response has already been ' + 'sent. Check your workflow.', params);
182 }
183 }
184
185 this._isSent = true;
186 this._content = content;
187 this._setCookieHeaders();
188 this._response.send(content);
189
190 return this;
191 }
192
193 /**
194 * Sets the rendered page state.
195 *
196 * @param {Object<string, *>} pageState The rendered page state.
197 * @return {Response} This response.
198 */
199 setPageState(pageState) {
200 if ($Debug) {
201 if (this._isSent === true) {
202 let params = this.getResponseParams();
203 params.pageState = pageState;
204
205 throw new _GenericError2.default('ima.router.Response:setState The response has already ' + 'been sent. Check your workflow.', params);
206 }
207 }
208
209 this._pageState = pageState;
210
211 return this;
212 }
213
214 /**
215 * Sets a cookie, which will be sent to the client with the response.
216 *
217 * @param {string} name The cookie name.
218 * @param {(boolean|number|string)} value The cookie value, will be
219 * converted to string.
220 * @param {{domain: string=, expires: (number|string)=, maxAge: number=}}
221 * options Cookie attributes. Only the attributes listed in the type
222 * annotation of this field are supported. For documentation and full
223 * list of cookie attributes
224 * see http://tools.ietf.org/html/rfc2965#page-5
225 * @return {Response} This response.
226 */
227 setCookie(name, value, options = {}) {
228 if ($Debug) {
229 if (this._isSent === true) {
230 let params = this.getResponseParams();
231 params.name = name;
232 params.value = value;
233 params.options = options;
234
235 throw new _GenericError2.default('ima.router.Response:setCookie The response has already ' + 'been sent. Check your workflow.', params);
236 }
237 }
238
239 let advancedOptions = Object.assign({}, this._cookieTransformFunction, options);
240
241 this._internalCookieStorage.set(name, {
242 value,
243 options: advancedOptions
244 });
245
246 return this;
247 }
248
249 /**
250 * Return object which contains response status, content and rendered
251 * page state.
252 *
253 * @return {{status: number, content: string, pageState: Object<string, *>}}
254 */
255 getResponseParams() {
256 return {
257 status: this._status,
258 content: this._content,
259 pageState: this._pageState
260 };
261 }
262
263 /**
264 * Return true if response is sent from server to client.
265 *
266 * @return {boolean}
267 */
268 isResponseSent() {
269 return this._isSent;
270 }
271
272 /**
273 * Set cookie headers for response.
274 */
275 _setCookieHeaders() {
276 for (let [name, param] of this._internalCookieStorage) {
277 let options = this._prepareCookieOptionsForExpress(param.options);
278 this._response.cookie(name, param.value, options);
279 }
280 }
281
282 /**
283 * Prepares cookie options for Express.
284 *
285 * @param {{domain: string=, expires: (number|string)=, maxAge: number=}}
286 * options Cookie attributes. Only the attributes listed in the type
287 * annotation of this field are supported. For documentation and full
288 * list of cookie attributes
289 * see http://tools.ietf.org/html/rfc2965#page-5
290 * @return {Object} Cookie options prepared for Express.
291 */
292 _prepareCookieOptionsForExpress(options) {
293 let expressOptions = Object.assign({}, options);
294
295 if (typeof expressOptions.maxAge === 'number') {
296 expressOptions.maxAge *= 1000;
297 } else {
298 delete expressOptions.maxAge;
299 }
300
301 return expressOptions;
302 }
303}
304exports.default = Response;
305
306typeof $IMA !== 'undefined' && $IMA !== null && $IMA.Loader && $IMA.Loader.register('ima/router/Response', [], function (_export, _context) {
307 'use strict';
308 return {
309 setters: [],
310 execute: function () {
311 _export('default', exports.default);
312 }
313 };
314});