1 |
|
2 | (function denali() {
|
3 | loader.scope('denali', '0.0.42', (loader) => {
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | loader.add('/app/actions/error.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
11 |
|
12 | "use strict";
|
13 | Object.defineProperty(exports, "__esModule", { value: true });
|
14 | const assert = require("assert");
|
15 | const action_1 = require("../../lib/runtime/action");
|
16 | const container_1 = require("../../lib/metal/container");
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | class ErrorAction extends action_1.default {
|
28 | constructor() {
|
29 | super(...arguments);
|
30 | this.logger = container_1.lookup('app:logger');
|
31 | this.parser = container_1.lookup('parser:json');
|
32 | }
|
33 | get originalAction() {
|
34 | return this.request._originalAction;
|
35 | }
|
36 | |
37 |
|
38 |
|
39 | async respond({ params }) {
|
40 | let error = params.error;
|
41 | assert(error, 'Error action must be invoked with an error as a param');
|
42 |
|
43 | if ((!error.status || error.status >= 500) && this.config.environment !== 'test') {
|
44 | this.logger.error(`Request ${this.request.id} errored:\n${error.stack || error.message}`);
|
45 | }
|
46 |
|
47 | error.status = error.statusCode = error.statusCode || 500;
|
48 |
|
49 |
|
50 | if (this.config.getWithDefault('logging', 'showDebuggingInfo', this.config.environment !== 'production')) {
|
51 | error.meta = error.meta || {};
|
52 | Object.assign(error.meta, {
|
53 | stack: error.stack.split('\n'),
|
54 | action: this.originalAction
|
55 | });
|
56 |
|
57 | }
|
58 | else {
|
59 | if (error.statusCode === 500) {
|
60 | error.message = 'Internal Error';
|
61 | }
|
62 | delete error.stack;
|
63 | }
|
64 | if (this.request.accepts('html') && this.config.environment !== 'production') {
|
65 | this.render(error.status, error, { view: 'error.html' });
|
66 | }
|
67 | else {
|
68 | this.render(error.status, error);
|
69 | }
|
70 | }
|
71 | }
|
72 | exports.default = ErrorAction;
|
73 |
|
74 | });
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | loader.add('/app/actions/index.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
82 |
|
83 | "use strict";
|
84 | Object.defineProperty(exports, "__esModule", { value: true });
|
85 | const action_1 = require("../../lib/runtime/action");
|
86 | class IndexAction extends action_1.default {
|
87 | respond() {
|
88 | return this.render(200, { hello: 'world' }, { serializer: 'json' });
|
89 | }
|
90 | }
|
91 | exports.default = IndexAction;
|
92 |
|
93 | });
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 | loader.add('/app/addon.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
101 |
|
102 | "use strict";
|
103 | Object.defineProperty(exports, "__esModule", { value: true });
|
104 | const lib_1 = require("../lib");
|
105 | class MyAddonAddon extends lib_1.Addon {
|
106 | }
|
107 | exports.default = MyAddonAddon;
|
108 |
|
109 | });
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | loader.add('/app/logger.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
117 |
|
118 | "use strict";
|
119 | Object.defineProperty(exports, "__esModule", { value: true });
|
120 | var logger_1 = require("../lib/runtime/logger");
|
121 | exports.default = logger_1.default;
|
122 |
|
123 | });
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | loader.add('/app/orm-adapters/application.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
131 |
|
132 | "use strict";
|
133 | Object.defineProperty(exports, "__esModule", { value: true });
|
134 | var memory_1 = require("../../lib/data/memory");
|
135 | exports.default = memory_1.default;
|
136 |
|
137 | });
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 | loader.add('/app/orm-adapters/memory.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
145 |
|
146 | "use strict";
|
147 | Object.defineProperty(exports, "__esModule", { value: true });
|
148 | var memory_1 = require("../../lib/data/memory");
|
149 | exports.default = memory_1.default;
|
150 |
|
151 | });
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 | loader.add('/app/parsers/application.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
159 |
|
160 | "use strict";
|
161 | Object.defineProperty(exports, "__esModule", { value: true });
|
162 | var json_api_1 = require("./json-api");
|
163 | exports.default = json_api_1.default;
|
164 |
|
165 | });
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 | loader.add('/app/parsers/json-api.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
173 |
|
174 | "use strict";
|
175 | Object.defineProperty(exports, "__esModule", { value: true });
|
176 | var json_api_1 = require("../../lib/parse/json-api");
|
177 | exports.default = json_api_1.default;
|
178 |
|
179 | });
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 | loader.add('/app/parsers/json.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
187 |
|
188 | "use strict";
|
189 | Object.defineProperty(exports, "__esModule", { value: true });
|
190 | var json_1 = require("../../lib/parse/json");
|
191 | exports.default = json_1.default;
|
192 |
|
193 | });
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | loader.add('/app/router.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
201 |
|
202 | "use strict";
|
203 | Object.defineProperty(exports, "__esModule", { value: true });
|
204 | var router_1 = require("../lib/runtime/router");
|
205 | exports.default = router_1.default;
|
206 |
|
207 | });
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 | loader.add('/app/serializers/application.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
215 |
|
216 | "use strict";
|
217 | Object.defineProperty(exports, "__esModule", { value: true });
|
218 | var json_api_1 = require("./json-api");
|
219 | exports.default = json_api_1.default;
|
220 |
|
221 | });
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 | loader.add('/app/serializers/json-api.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
229 |
|
230 | "use strict";
|
231 | Object.defineProperty(exports, "__esModule", { value: true });
|
232 | var json_api_1 = require("../../lib/render/json-api");
|
233 | exports.default = json_api_1.default;
|
234 |
|
235 | });
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 | loader.add('/app/serializers/json.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
243 |
|
244 | "use strict";
|
245 | Object.defineProperty(exports, "__esModule", { value: true });
|
246 | var json_1 = require("../../lib/render/json");
|
247 | exports.default = json_1.default;
|
248 |
|
249 | });
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 | loader.add('/app/services/config.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
257 |
|
258 | "use strict";
|
259 | Object.defineProperty(exports, "__esModule", { value: true });
|
260 | var config_1 = require("../../lib/runtime/config");
|
261 | exports.default = config_1.default;
|
262 |
|
263 | });
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 | loader.add('/app/views/error.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
271 |
|
272 | "use strict";
|
273 | Object.defineProperty(exports, "__esModule", { value: true });
|
274 | const lodash_1 = require("lodash");
|
275 | const view_1 = require("../../lib/render/view");
|
276 | let template = lodash_1.template(`
|
277 | <html>
|
278 | <head>
|
279 | <style>
|
280 | body {
|
281 | font-family: Arial, Helvetica, sans-serif;
|
282 | background: #f7f7f7;
|
283 | margin: 0;
|
284 | }
|
285 | pre {
|
286 | font-family: Inconsolata, Monaco, Menlo, monospace;
|
287 | }
|
288 | .headline {
|
289 | background: #fff;
|
290 | padding: 30px;
|
291 | color: #DC4B4B;
|
292 | font-family: Inconsolata, Monaco, Menlo, monospace;
|
293 | border-bottom: 1px solid #ddd;
|
294 | margin-bottom: 0;
|
295 | }
|
296 | .lead {
|
297 | display: block;
|
298 | margin-bottom: 7px;
|
299 | color: #aaa;
|
300 | font-size: 14px;
|
301 | font-family: Arial, Helvetica, sans-serif;
|
302 | font-weight: 300;
|
303 | }
|
304 | .details {
|
305 | padding: 30px;
|
306 | }
|
307 | </style>
|
308 | </head>
|
309 | <body>
|
310 | <h1 class='headline'>
|
311 | <small class='lead'>There was an error with this request:</small>
|
312 | <%= data.error.message %>
|
313 | </h1>
|
314 | <div class='details'>
|
315 | <% if (data.error.action) { %>
|
316 | <h2 class='source'>from <%= data.error.action %></h2>
|
317 | <% } %>
|
318 | <h5>Stacktrace:</h5>
|
319 | <pre><code><%= data.error.stack %></code></pre>
|
320 | </div>
|
321 | </body>
|
322 | </html>
|
323 | `, {
|
324 | variable: 'data'
|
325 | });
|
326 | class ErrorView extends view_1.default {
|
327 | async render(action, response, error, options) {
|
328 | response.setHeader('Content-type', 'text/html');
|
329 | error.stack = error.stack.replace('\\n', '\n');
|
330 | response.write(template({ error }));
|
331 | response.end();
|
332 | }
|
333 | }
|
334 | exports.default = ErrorView;
|
335 |
|
336 | });
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 | loader.add('/config/environment.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
344 |
|
345 | module.exports = function baseConfig(environment, appConfig) {
|
346 | if (!appConfig.logging) {
|
347 | appConfig.logging = {};
|
348 | }
|
349 | if (!appConfig.logging.hasOwnProperty('showDebuggingInfo')) {
|
350 | appConfig.logging.showDebuggingInfo = environment !== 'production';
|
351 | }
|
352 | };
|
353 |
|
354 | });
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 | loader.add('/config/initializers/define-orm-models.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
362 |
|
363 | "use strict";
|
364 | Object.defineProperty(exports, "__esModule", { value: true });
|
365 | const lodash_1 = require("lodash");
|
366 | const container_1 = require("../../lib/metal/container");
|
367 | exports.default = {
|
368 | name: 'define-orm-models',
|
369 | |
370 |
|
371 |
|
372 |
|
373 | async initialize(application) {
|
374 | let models = container_1.default.lookupAll('model');
|
375 | let modelsGroupedByAdapter = new Map();
|
376 | lodash_1.forEach(models, (ModelClass, modelName) => {
|
377 | if (ModelClass.hasOwnProperty('abstract') && ModelClass.abstract) {
|
378 | return;
|
379 | }
|
380 | let Adapter = container_1.lookup(`orm-adapter:${modelName}`, { loose: true }) || container_1.default.lookup('orm-adapter:application');
|
381 | if (!modelsGroupedByAdapter.has(Adapter)) {
|
382 | modelsGroupedByAdapter.set(Adapter, []);
|
383 | }
|
384 | modelsGroupedByAdapter.get(Adapter).push(ModelClass);
|
385 | });
|
386 | for (let [Adapter, models] of modelsGroupedByAdapter) {
|
387 | if (Adapter.defineModels) {
|
388 | await Adapter.defineModels(models);
|
389 | }
|
390 | }
|
391 | }
|
392 | };
|
393 |
|
394 | });
|
395 |
|
396 |
|
397 |
|
398 |
|
399 |
|
400 |
|
401 | loader.add('/config/middleware.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
402 |
|
403 | "use strict";
|
404 | Object.defineProperty(exports, "__esModule", { value: true });
|
405 | const lodash_1 = require("lodash");
|
406 | const timing = require("response-time");
|
407 | const compression = require("compression");
|
408 | const cookies = require("cookie-parser");
|
409 | const cors = require("cors");
|
410 | const helmet = require("helmet");
|
411 | const morgan = require("morgan");
|
412 |
|
413 |
|
414 |
|
415 |
|
416 | function baseMiddleware(router, application) {
|
417 | let config = application.config;
|
418 | |
419 |
|
420 |
|
421 |
|
422 |
|
423 | function isEnabled(prop) {
|
424 | return config.get(prop) == null || config.get(prop, 'enabled') !== false;
|
425 | }
|
426 | if (isEnabled('timing')) {
|
427 | router.use(timing());
|
428 | }
|
429 | if (isEnabled('logging')) {
|
430 | let defaultLoggingFormat = application.environment === 'production' ? 'combined' : 'dev';
|
431 | let defaultLoggingOptions = {
|
432 |
|
433 | skip() {
|
434 | return application.environment === 'test';
|
435 | }
|
436 | };
|
437 | let format = config.getWithDefault('logging', 'format', defaultLoggingFormat);
|
438 | let options = lodash_1.defaults(config.getWithDefault('logging', {}), defaultLoggingOptions);
|
439 | router.use(morgan(format, options));
|
440 |
|
441 | morgan.token('res', (req, res, field) => {
|
442 | let header = res.getHeader(field);
|
443 | if (typeof header === 'number') {
|
444 | header = String(header);
|
445 | }
|
446 | else if (Array.isArray(header)) {
|
447 | header = header.join(', ');
|
448 | }
|
449 | return header;
|
450 | });
|
451 | }
|
452 | if (isEnabled('compression')) {
|
453 | router.use(compression());
|
454 | }
|
455 | if (isEnabled('cookies')) {
|
456 | router.use(cookies(config.get('cookies')));
|
457 | }
|
458 | if (isEnabled('cors')) {
|
459 | router.use(cors(config.get('cors')));
|
460 | }
|
461 | if (isEnabled('xssFilter')) {
|
462 | router.use(helmet.xssFilter());
|
463 | }
|
464 | if (isEnabled('frameguard')) {
|
465 | router.use(helmet.frameguard());
|
466 | }
|
467 | if (isEnabled('hidePoweredBy')) {
|
468 | router.use(helmet.hidePoweredBy());
|
469 | }
|
470 | if (isEnabled('ieNoOpen')) {
|
471 | router.use(helmet.ieNoOpen());
|
472 | }
|
473 | if (isEnabled('noSniff')) {
|
474 | router.use(helmet.noSniff());
|
475 | }
|
476 | }
|
477 | exports.default = baseMiddleware;
|
478 |
|
479 | });
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 | loader.add('/lib/data/descriptors.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
487 |
|
488 | "use strict";
|
489 | Object.defineProperty(exports, "__esModule", { value: true });
|
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 | class Descriptor {
|
496 | |
497 |
|
498 |
|
499 | constructor(options = {}) {
|
500 | this.options = options;
|
501 | }
|
502 | }
|
503 | exports.Descriptor = Descriptor;
|
504 |
|
505 |
|
506 |
|
507 |
|
508 |
|
509 |
|
510 |
|
511 |
|
512 |
|
513 |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 |
|
520 |
|
521 |
|
522 |
|
523 |
|
524 |
|
525 |
|
526 |
|
527 |
|
528 |
|
529 | class AttributeDescriptor extends Descriptor {
|
530 | constructor(datatype, options) {
|
531 | super(options);
|
532 | this.datatype = datatype;
|
533 | |
534 |
|
535 |
|
536 |
|
537 |
|
538 | this.isAttribute = true;
|
539 | }
|
540 | }
|
541 | exports.AttributeDescriptor = AttributeDescriptor;
|
542 |
|
543 |
|
544 |
|
545 |
|
546 |
|
547 |
|
548 | function attr(datatype, options) {
|
549 | return new AttributeDescriptor(datatype, options);
|
550 | }
|
551 | exports.attr = attr;
|
552 |
|
553 |
|
554 |
|
555 |
|
556 |
|
557 |
|
558 |
|
559 |
|
560 |
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 |
|
567 |
|
568 |
|
569 |
|
570 |
|
571 |
|
572 |
|
573 |
|
574 |
|
575 |
|
576 | class HasManyRelationshipDescriptor extends Descriptor {
|
577 | constructor(relatedModelName, options) {
|
578 | super(options);
|
579 | this.relatedModelName = relatedModelName;
|
580 | |
581 |
|
582 |
|
583 |
|
584 |
|
585 | this.isRelationship = true;
|
586 | |
587 |
|
588 |
|
589 |
|
590 |
|
591 | this.mode = 'hasMany';
|
592 | }
|
593 | }
|
594 | exports.HasManyRelationshipDescriptor = HasManyRelationshipDescriptor;
|
595 |
|
596 |
|
597 |
|
598 |
|
599 |
|
600 |
|
601 | function hasMany(relatedModelName, options) {
|
602 | return new HasManyRelationshipDescriptor(relatedModelName, options);
|
603 | }
|
604 | exports.hasMany = hasMany;
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 |
|
611 |
|
612 |
|
613 |
|
614 |
|
615 |
|
616 |
|
617 |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 |
|
628 |
|
629 | class HasOneRelationshipDescriptor extends Descriptor {
|
630 | constructor(relatedModelName, options) {
|
631 | super(options);
|
632 | this.relatedModelName = relatedModelName;
|
633 | |
634 |
|
635 |
|
636 |
|
637 |
|
638 | this.isRelationship = true;
|
639 | |
640 |
|
641 |
|
642 |
|
643 |
|
644 | this.mode = 'hasOne';
|
645 | }
|
646 | }
|
647 | exports.HasOneRelationshipDescriptor = HasOneRelationshipDescriptor;
|
648 |
|
649 |
|
650 |
|
651 |
|
652 |
|
653 |
|
654 | function hasOne(relatedModelName, options) {
|
655 | return new HasOneRelationshipDescriptor(relatedModelName, options);
|
656 | }
|
657 | exports.hasOne = hasOne;
|
658 |
|
659 | });
|
660 |
|
661 |
|
662 |
|
663 |
|
664 |
|
665 |
|
666 | loader.add('/lib/data/memory.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
667 |
|
668 | "use strict";
|
669 | Object.defineProperty(exports, "__esModule", { value: true });
|
670 | const lodash_1 = require("lodash");
|
671 | const orm_adapter_1 = require("./orm-adapter");
|
672 | const assert = require("assert");
|
673 | const inflection_1 = require("inflection");
|
674 | let guid = 0;
|
675 |
|
676 |
|
677 |
|
678 |
|
679 |
|
680 |
|
681 |
|
682 | class MemoryAdapter extends orm_adapter_1.default {
|
683 | constructor() {
|
684 | super(...arguments);
|
685 | |
686 |
|
687 |
|
688 |
|
689 | this._cache = {};
|
690 | }
|
691 | |
692 |
|
693 |
|
694 |
|
695 |
|
696 | _cacheFor(type) {
|
697 | if (!this._cache[type]) {
|
698 | this._cache[type] = {};
|
699 | }
|
700 | return this._cache[type];
|
701 | }
|
702 |
|
703 | async find(type, id) {
|
704 | return this._cacheFor(type)[id] || null;
|
705 | }
|
706 | async queryOne(type, query) {
|
707 | return lodash_1.find(this._cacheFor(type), query) || null;
|
708 | }
|
709 | async all(type) {
|
710 | return lodash_1.values(this._cacheFor(type));
|
711 | }
|
712 | async query(type, query) {
|
713 | return lodash_1.filter(this._cacheFor(type), query);
|
714 | }
|
715 | buildRecord(type, data = {}) {
|
716 | this._cacheFor(type);
|
717 | return data;
|
718 | }
|
719 | idFor(model) {
|
720 | return model.record.id;
|
721 | }
|
722 | setId(model, value) {
|
723 | let collection = this._cacheFor(model.modelName);
|
724 | delete collection[model.record.id];
|
725 | model.record.id = value;
|
726 | collection[value] = model.record;
|
727 | }
|
728 | getAttribute(model, property) {
|
729 | return model.record[property] === undefined ? null : model.record[property];
|
730 | }
|
731 | setAttribute(model, property, value) {
|
732 | model.record[property] = value;
|
733 | return true;
|
734 | }
|
735 | deleteAttribute(model, property) {
|
736 | model.record[property] = null;
|
737 | return true;
|
738 | }
|
739 | async getRelated(model, relationship, descriptor, query) {
|
740 | let relatedCollection = this._cacheFor(descriptor.relatedModelName);
|
741 | if (descriptor.mode === 'hasMany') {
|
742 | let related = lodash_1.filter(relatedCollection, (relatedRecord) => {
|
743 | let relatedIds = model.record[`${inflection_1.singularize(relationship)}_ids`];
|
744 | return relatedIds && relatedIds.includes(relatedRecord.id);
|
745 | });
|
746 | if (query) {
|
747 | related = lodash_1.filter(related, query);
|
748 | }
|
749 | return related;
|
750 | }
|
751 | return this.queryOne(descriptor.relatedModelName, { id: model.record[`${relationship}_id`] });
|
752 | }
|
753 | async setRelated(model, relationship, descriptor, relatedModels) {
|
754 | if (Array.isArray(relatedModels)) {
|
755 | assert(descriptor.mode === 'hasMany', `You tried to set ${relationship} to an array of related records, but it is a hasOne relationship`);
|
756 | model.record[`${inflection_1.singularize(relationship)}_ids`] = lodash_1.map(relatedModels, 'record.id');
|
757 | }
|
758 | else {
|
759 | model.record[`${relationship}_id`] = relatedModels.record.id;
|
760 | }
|
761 | }
|
762 | async addRelated(model, relationship, descriptor, relatedModel) {
|
763 | let relatedIds = model.record[`${inflection_1.singularize(relationship)}_ids`];
|
764 | if (!relatedIds) {
|
765 | relatedIds = model.record[`${inflection_1.singularize(relationship)}_ids`] = [];
|
766 | }
|
767 | relatedIds.push(relatedModel.id);
|
768 | }
|
769 | async removeRelated(model, relationship, descriptor, relatedModel) {
|
770 | lodash_1.remove(model.record[`${inflection_1.singularize(relationship)}_ids`], (id) => id === relatedModel.id);
|
771 | }
|
772 | async saveRecord(model) {
|
773 | let collection = this._cacheFor(model.modelName);
|
774 | if (model.record.id == null) {
|
775 | guid += 1;
|
776 | model.record.id = guid;
|
777 | }
|
778 | collection[model.record.id] = model.record;
|
779 | return model.record;
|
780 | }
|
781 | async deleteRecord(model) {
|
782 | let collection = this._cacheFor(model.modelName);
|
783 | delete collection[model.record.id];
|
784 | }
|
785 | }
|
786 | exports.default = MemoryAdapter;
|
787 |
|
788 | });
|
789 |
|
790 |
|
791 |
|
792 |
|
793 |
|
794 |
|
795 | loader.add('/lib/data/model.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
796 |
|
797 | "use strict";
|
798 | Object.defineProperty(exports, "__esModule", { value: true });
|
799 | const assert = require("assert");
|
800 | const util = require("util");
|
801 | const createDebug = require("debug");
|
802 | const inflection_1 = require("inflection");
|
803 | const lodash_1 = require("lodash");
|
804 | const object_1 = require("../metal/object");
|
805 | const container_1 = require("../metal/container");
|
806 | const debug = createDebug('denali:model');
|
807 | const augmentedWithAccessors = Symbol();
|
808 |
|
809 |
|
810 |
|
811 |
|
812 |
|
813 |
|
814 |
|
815 |
|
816 |
|
817 |
|
818 |
|
819 |
|
820 |
|
821 |
|
822 |
|
823 |
|
824 |
|
825 |
|
826 | class Model extends object_1.default {
|
827 | |
828 |
|
829 |
|
830 | constructor(data, options) {
|
831 | super();
|
832 | |
833 |
|
834 |
|
835 |
|
836 |
|
837 |
|
838 | this.record = null;
|
839 | this.constructor._augmentWithSchemaAccessors();
|
840 | this.record = this.constructor.adapter.buildRecord(this.modelName, data, options);
|
841 | }
|
842 | |
843 |
|
844 |
|
845 | static get attributes() {
|
846 |
|
847 |
|
848 | return lodash_1.pickBy(this.schema, (descriptor) => descriptor.isAttribute);
|
849 | }
|
850 | |
851 |
|
852 |
|
853 | static get relationships() {
|
854 |
|
855 |
|
856 | return lodash_1.pickBy(this.schema, (descriptor) => descriptor.isRelationship);
|
857 | }
|
858 | static _augmentWithSchemaAccessors() {
|
859 | if (this.prototype[augmentedWithAccessors]) {
|
860 | return;
|
861 | }
|
862 | this.prototype[augmentedWithAccessors] = true;
|
863 | lodash_1.forEach(this.schema, (descriptor, name) => {
|
864 | if (descriptor.isAttribute) {
|
865 | Object.defineProperty(this.prototype, name, {
|
866 | configurable: true,
|
867 | get() {
|
868 | return this.constructor.adapter.getAttribute(this, name);
|
869 | },
|
870 | set(newValue) {
|
871 | return this.constructor.adapter.setAttribute(this, name, newValue);
|
872 | }
|
873 | });
|
874 | }
|
875 | else {
|
876 |
|
877 | let methodRoot = lodash_1.upperFirst(name);
|
878 |
|
879 | Object.defineProperty(this.prototype, `get${methodRoot}`, {
|
880 | configurable: true,
|
881 | value(options) { return this.getRelated(name, options); }
|
882 | });
|
883 |
|
884 | Object.defineProperty(this.prototype, `set${methodRoot}`, {
|
885 | configurable: true,
|
886 | value(relatedModels, options) {
|
887 | return this.setRelated(name, relatedModels, options);
|
888 | }
|
889 | });
|
890 | if (descriptor.mode === 'hasMany') {
|
891 | let singularRoot = inflection_1.singularize(methodRoot);
|
892 |
|
893 | Object.defineProperty(this.prototype, `add${singularRoot}`, {
|
894 | configurable: true,
|
895 | value(relatedModel, options) {
|
896 | return this.addRelated(name, relatedModel, options);
|
897 | }
|
898 | });
|
899 |
|
900 | Object.defineProperty(this.prototype, `remove${singularRoot}`, {
|
901 | configurable: true,
|
902 | value(relatedModel, options) {
|
903 | return this.removeRelated(name, relatedModel, options);
|
904 | }
|
905 | });
|
906 | }
|
907 | }
|
908 | });
|
909 | }
|
910 | |
911 |
|
912 |
|
913 |
|
914 |
|
915 | static build(record) {
|
916 | let model = new this();
|
917 | model.record = record;
|
918 | return model;
|
919 | }
|
920 | |
921 |
|
922 |
|
923 |
|
924 |
|
925 |
|
926 |
|
927 | static async find(id, options) {
|
928 | assert(id != null, `You must pass an id to Model.find(id)`);
|
929 | debug(`${this.modelName} find: ${id}`);
|
930 | let record = await this.adapter.find(this.modelName, id, options);
|
931 | if (!record) {
|
932 | return null;
|
933 | }
|
934 | return this.build(record);
|
935 | }
|
936 | |
937 |
|
938 |
|
939 |
|
940 |
|
941 |
|
942 |
|
943 | static async queryOne(query, options) {
|
944 | assert(query != null, `You must pass a query to Model.queryOne(conditions)`);
|
945 | debug(`${this.modelName} queryOne: ${util.inspect(query)}`);
|
946 | let record = await this.adapter.queryOne(this.modelName, query, options);
|
947 | if (!record) {
|
948 | return null;
|
949 | }
|
950 | return this.build(record);
|
951 | }
|
952 | |
953 |
|
954 |
|
955 |
|
956 |
|
957 |
|
958 |
|
959 | static async query(query, options) {
|
960 | assert(query != null, `You must pass a query to Model.query(conditions)`);
|
961 | debug(`${this.modelName} query: ${util.inspect(query)}`);
|
962 | let records = await this.adapter.query(this.modelName, query, options);
|
963 | return records.map((record) => this.build(record));
|
964 | }
|
965 | |
966 |
|
967 |
|
968 |
|
969 |
|
970 |
|
971 | static async all(options) {
|
972 | debug(`${this.modelName} all`);
|
973 | let result = await this.adapter.all(this.modelName, options);
|
974 | return result.map((record) => this.build(record));
|
975 | }
|
976 | |
977 |
|
978 |
|
979 |
|
980 |
|
981 |
|
982 |
|
983 |
|
984 | static async create(data = {}, options) {
|
985 | let model = new this(data, options);
|
986 | return model.save();
|
987 | }
|
988 | |
989 |
|
990 |
|
991 |
|
992 |
|
993 |
|
994 | static get adapter() {
|
995 | return container_1.lookup(`orm-adapter:${this.modelName}`);
|
996 | }
|
997 | |
998 |
|
999 |
|
1000 |
|
1001 |
|
1002 |
|
1003 | static get modelName() {
|
1004 | let name = this.name;
|
1005 | if (name.endsWith('Model')) {
|
1006 | name = name.substring(0, name.length - 'Model'.length);
|
1007 | }
|
1008 | name = lodash_1.kebabCase(name);
|
1009 | return name;
|
1010 | }
|
1011 | |
1012 |
|
1013 |
|
1014 |
|
1015 |
|
1016 |
|
1017 | get modelName() {
|
1018 | return this.constructor.modelName;
|
1019 | }
|
1020 | |
1021 |
|
1022 |
|
1023 |
|
1024 |
|
1025 | get id() {
|
1026 | return this.constructor.adapter.idFor(this);
|
1027 | }
|
1028 | set id(value) {
|
1029 | this.constructor.adapter.setId(this, value);
|
1030 | }
|
1031 | |
1032 |
|
1033 |
|
1034 |
|
1035 |
|
1036 | async save(options) {
|
1037 | debug(`saving ${this.toString()}`);
|
1038 | await this.constructor.adapter.saveRecord(this, options);
|
1039 | return this;
|
1040 | }
|
1041 | |
1042 |
|
1043 |
|
1044 |
|
1045 |
|
1046 | async delete(options) {
|
1047 | debug(`deleting ${this.toString()}`);
|
1048 | await this.constructor.adapter.deleteRecord(this, options);
|
1049 | }
|
1050 | |
1051 |
|
1052 |
|
1053 |
|
1054 |
|
1055 | async getRelated(relationshipName, options) {
|
1056 | let descriptor = this.constructor.schema[relationshipName];
|
1057 | assert(descriptor && descriptor.isRelationship, `You tried to fetch related ${relationshipName}, but no such relationship exists on ${this.modelName}`);
|
1058 | let RelatedModel = container_1.lookup(`model:${descriptor.relatedModelName}`);
|
1059 | let results = await this.constructor.adapter.getRelated(this, relationshipName, descriptor, options);
|
1060 | if (descriptor.mode === 'hasOne') {
|
1061 | assert(!Array.isArray(results), `The ${this.modelName} ORM adapter returned an array for the hasOne '${relationshipName}' relationship - it should return either an ORM record or null.`);
|
1062 | return results ? RelatedModel.create(results) : null;
|
1063 | }
|
1064 | assert(Array.isArray(results), `The ${this.modelName} ORM adapter did not return an array for the hasMany '${relationshipName}' relationship - it should return an array (empty if no related records exist).`);
|
1065 | return results.map((record) => RelatedModel.build(record));
|
1066 | }
|
1067 | |
1068 |
|
1069 |
|
1070 |
|
1071 |
|
1072 |
|
1073 | async setRelated(relationshipName, relatedModels, options) {
|
1074 | let descriptor = this.constructor.schema[relationshipName];
|
1075 | await this.constructor.adapter.setRelated(this, relationshipName, descriptor, relatedModels, options);
|
1076 | }
|
1077 | |
1078 |
|
1079 |
|
1080 |
|
1081 |
|
1082 | async addRelated(relationshipName, relatedModel, options) {
|
1083 | let descriptor = this.constructor.schema[inflection_1.pluralize(relationshipName)];
|
1084 | await this.constructor.adapter.addRelated(this, relationshipName, descriptor, relatedModel, options);
|
1085 | }
|
1086 | |
1087 |
|
1088 |
|
1089 |
|
1090 |
|
1091 | async removeRelated(relationshipName, relatedModel, options) {
|
1092 | let descriptor = this.constructor.schema[inflection_1.pluralize(relationshipName)];
|
1093 | await this.constructor.adapter.removeRelated(this, relationshipName, descriptor, relatedModel, options);
|
1094 | }
|
1095 | |
1096 |
|
1097 |
|
1098 |
|
1099 |
|
1100 |
|
1101 | inspect() {
|
1102 | let attributesSummary = [];
|
1103 | lodash_1.forEach(this.constructor.schema, (descriptor, name) => {
|
1104 | attributesSummary.push(`${name}=${util.inspect(this[name])}`);
|
1105 | });
|
1106 | return `<${lodash_1.startCase(this.modelName)}:${this.id == null ? '-new-' : this.id} ${attributesSummary.join(', ')}>`;
|
1107 | }
|
1108 | |
1109 |
|
1110 |
|
1111 |
|
1112 |
|
1113 | toString() {
|
1114 | return `<${lodash_1.startCase(this.modelName)}:${this.id == null ? '-new-' : this.id}>`;
|
1115 | }
|
1116 | }
|
1117 |
|
1118 |
|
1119 |
|
1120 |
|
1121 |
|
1122 |
|
1123 | Model.abstract = false;
|
1124 |
|
1125 |
|
1126 |
|
1127 |
|
1128 | Model.schema = {};
|
1129 | exports.default = Model;
|
1130 |
|
1131 | });
|
1132 |
|
1133 |
|
1134 |
|
1135 |
|
1136 |
|
1137 |
|
1138 | loader.add('/lib/data/orm-adapter.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
1139 |
|
1140 | "use strict";
|
1141 | Object.defineProperty(exports, "__esModule", { value: true });
|
1142 | const object_1 = require("../metal/object");
|
1143 |
|
1144 |
|
1145 |
|
1146 |
|
1147 |
|
1148 |
|
1149 |
|
1150 |
|
1151 |
|
1152 |
|
1153 |
|
1154 |
|
1155 |
|
1156 |
|
1157 |
|
1158 |
|
1159 |
|
1160 |
|
1161 |
|
1162 |
|
1163 |
|
1164 |
|
1165 |
|
1166 |
|
1167 |
|
1168 |
|
1169 |
|
1170 | class ORMAdapter extends object_1.default {
|
1171 | }
|
1172 | exports.default = ORMAdapter;
|
1173 |
|
1174 | });
|
1175 |
|
1176 |
|
1177 |
|
1178 |
|
1179 |
|
1180 |
|
1181 | loader.add('/lib/index.js', {"isMain":true}, function(module, exports, require, __dirname, __filename) {
|
1182 |
|
1183 | "use strict";
|
1184 |
|
1185 |
|
1186 |
|
1187 |
|
1188 |
|
1189 |
|
1190 |
|
1191 |
|
1192 |
|
1193 |
|
1194 | Object.defineProperty(exports, "__esModule", { value: true });
|
1195 |
|
1196 | const descriptors_1 = require("./data/descriptors");
|
1197 | exports.attr = descriptors_1.attr;
|
1198 | exports.hasMany = descriptors_1.hasMany;
|
1199 | exports.hasOne = descriptors_1.hasOne;
|
1200 | exports.HasOneRelationshipDescriptor = descriptors_1.HasOneRelationshipDescriptor;
|
1201 | exports.HasManyRelationshipDescriptor = descriptors_1.HasManyRelationshipDescriptor;
|
1202 | exports.AttributeDescriptor = descriptors_1.AttributeDescriptor;
|
1203 | const model_1 = require("./data/model");
|
1204 | exports.Model = model_1.default;
|
1205 | const orm_adapter_1 = require("./data/orm-adapter");
|
1206 | exports.ORMAdapter = orm_adapter_1.default;
|
1207 | const memory_1 = require("./data/memory");
|
1208 | exports.MemoryAdapter = memory_1.default;
|
1209 |
|
1210 | const serializer_1 = require("./render/serializer");
|
1211 | exports.Serializer = serializer_1.default;
|
1212 | const json_1 = require("./render/json");
|
1213 | exports.JSONSerializer = json_1.default;
|
1214 | const json_api_1 = require("./render/json-api");
|
1215 | exports.JSONAPISerializer = json_api_1.default;
|
1216 | const view_1 = require("./render/view");
|
1217 | exports.View = view_1.default;
|
1218 |
|
1219 | const parser_1 = require("./parse/parser");
|
1220 | exports.Parser = parser_1.default;
|
1221 | const json_2 = require("./parse/json");
|
1222 | exports.JSONParser = json_2.default;
|
1223 | const json_api_2 = require("./parse/json-api");
|
1224 | exports.JSONAPIParser = json_api_2.default;
|
1225 |
|
1226 | const instrumentation_1 = require("./metal/instrumentation");
|
1227 | exports.Instrumentation = instrumentation_1.default;
|
1228 | const mixin_1 = require("./metal/mixin");
|
1229 | exports.mixin = mixin_1.default;
|
1230 | exports.createMixin = mixin_1.createMixin;
|
1231 | const container_1 = require("./metal/container");
|
1232 | exports.container = container_1.default;
|
1233 | exports.lookup = container_1.lookup;
|
1234 | exports.Container = container_1.Container;
|
1235 | const resolver_1 = require("./metal/resolver");
|
1236 | exports.Resolver = resolver_1.default;
|
1237 | const object_1 = require("./metal/object");
|
1238 | exports.DenaliObject = object_1.default;
|
1239 |
|
1240 | const action_1 = require("./runtime/action");
|
1241 | exports.Action = action_1.default;
|
1242 | const addon_1 = require("./runtime/addon");
|
1243 | exports.Addon = addon_1.default;
|
1244 | const application_1 = require("./runtime/application");
|
1245 | exports.Application = application_1.default;
|
1246 | const errors_1 = require("./runtime/errors");
|
1247 | exports.Errors = errors_1.default;
|
1248 | const logger_1 = require("./runtime/logger");
|
1249 | exports.Logger = logger_1.default;
|
1250 | const request_1 = require("./runtime/request");
|
1251 | exports.Request = request_1.default;
|
1252 | const router_1 = require("./runtime/router");
|
1253 | exports.Router = router_1.default;
|
1254 | const service_1 = require("./runtime/service");
|
1255 | exports.Service = service_1.default;
|
1256 | const config_1 = require("./runtime/config");
|
1257 | exports.ConfigService = config_1.default;
|
1258 |
|
1259 | const acceptance_test_1 = require("./test/acceptance-test");
|
1260 | exports.setupAcceptanceTest = acceptance_test_1.default;
|
1261 | exports.AcceptanceTest = acceptance_test_1.AcceptanceTest;
|
1262 | const unit_test_1 = require("./test/unit-test");
|
1263 | exports.setupUnitTest = unit_test_1.default;
|
1264 | exports.UnitTest = unit_test_1.UnitTest;
|
1265 | const mock_request_1 = require("./test/mock-request");
|
1266 | exports.MockRequest = mock_request_1.default;
|
1267 | const mock_response_1 = require("./test/mock-response");
|
1268 | exports.MockResponse = mock_response_1.default;
|
1269 |
|
1270 | });
|
1271 |
|
1272 |
|
1273 |
|
1274 |
|
1275 |
|
1276 |
|
1277 | loader.add('/lib/metal/container.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
1278 |
|
1279 | "use strict";
|
1280 | Object.defineProperty(exports, "__esModule", { value: true });
|
1281 | const assert = require("assert");
|
1282 | const lodash_1 = require("lodash");
|
1283 | const resolver_1 = require("./resolver");
|
1284 | const strings_1 = require("../utils/strings");
|
1285 | const crawl = require("tree-crawl");
|
1286 | const DEFAULT_OPTIONS = {
|
1287 | singleton: true,
|
1288 | fallbacks: []
|
1289 | };
|
1290 |
|
1291 |
|
1292 |
|
1293 |
|
1294 |
|
1295 |
|
1296 |
|
1297 |
|
1298 |
|
1299 |
|
1300 |
|
1301 |
|
1302 |
|
1303 | class Container {
|
1304 | constructor() {
|
1305 | |
1306 |
|
1307 |
|
1308 | this.registry = {};
|
1309 | |
1310 |
|
1311 |
|
1312 |
|
1313 |
|
1314 |
|
1315 | this.resolvers = [];
|
1316 | |
1317 |
|
1318 |
|
1319 | this.lookups = {};
|
1320 | |
1321 |
|
1322 |
|
1323 |
|
1324 | this.options = {
|
1325 | app: { singleton: true },
|
1326 | 'app:application': { singleton: false },
|
1327 | action: { singleton: false },
|
1328 | config: { singleton: false },
|
1329 | initializer: { singleton: false },
|
1330 | 'orm-adapter': { singleton: true, fallbacks: ['orm-adapter:application'] },
|
1331 | model: { singleton: false },
|
1332 | parser: { singleton: true, fallbacks: ['parser:application'] },
|
1333 | serializer: { singleton: true, fallbacks: ['serializer:application'] },
|
1334 | service: { singleton: true },
|
1335 | view: { singleton: true }
|
1336 | };
|
1337 | }
|
1338 | |
1339 |
|
1340 |
|
1341 | loadBundle(loader) {
|
1342 | this.loader = loader;
|
1343 | crawl(loader, this.loadBundleScope.bind(this), {
|
1344 | order: 'bfs',
|
1345 | getChildren(loader) {
|
1346 | return Array.from(loader.children.values());
|
1347 | }
|
1348 | });
|
1349 | }
|
1350 | |
1351 |
|
1352 |
|
1353 |
|
1354 |
|
1355 |
|
1356 | loadBundleScope(loader) {
|
1357 | let LoaderResolver;
|
1358 | try {
|
1359 | LoaderResolver = loader.load('resolver');
|
1360 | }
|
1361 | catch (e) {
|
1362 | LoaderResolver = resolver_1.default;
|
1363 | }
|
1364 | let resolver = new LoaderResolver(loader);
|
1365 | this.resolvers.push(resolver);
|
1366 | loader.resolver = resolver;
|
1367 | }
|
1368 | |
1369 |
|
1370 |
|
1371 |
|
1372 |
|
1373 |
|
1374 | register(specifier, entry, options) {
|
1375 | this.registry[specifier] = entry;
|
1376 | if (options) {
|
1377 | lodash_1.forOwn(options, (value, key) => {
|
1378 | this.setOption(specifier, key, value);
|
1379 | });
|
1380 | }
|
1381 | }
|
1382 | lookup(specifier, options = {}) {
|
1383 |
|
1384 | if (options.raw) {
|
1385 | let entry = this.lookupRaw(specifier);
|
1386 | if (entry === false && !options.loose) {
|
1387 | throw new ContainerEntryNotFound(specifier, this.registry, this.resolvers);
|
1388 | }
|
1389 | return entry;
|
1390 | }
|
1391 |
|
1392 | if (this.lookups[specifier]) {
|
1393 | return this.lookups[specifier];
|
1394 | }
|
1395 |
|
1396 | let entry = this.lookupRaw(specifier);
|
1397 |
|
1398 | if (entry !== false) {
|
1399 | entry = this.instantiateSingletons(specifier, entry);
|
1400 | this.lookups[specifier] = entry;
|
1401 | return entry;
|
1402 | }
|
1403 |
|
1404 | let fallbacks = this.getOption(specifier, 'fallbacks').slice(0);
|
1405 | let fallback;
|
1406 | while ((fallback = fallbacks.shift()) && (fallback !== specifier)) {
|
1407 | entry = this.lookup(fallback, options);
|
1408 | if (entry) {
|
1409 | break;
|
1410 | }
|
1411 | }
|
1412 | if (entry !== false) {
|
1413 |
|
1414 |
|
1415 | this.lookups[specifier] = entry;
|
1416 | return entry;
|
1417 | }
|
1418 | if (options.loose) {
|
1419 | return false;
|
1420 | }
|
1421 | throw new ContainerEntryNotFound(specifier, this.registry, this.resolvers);
|
1422 | }
|
1423 | instantiateSingletons(specifier, entry) {
|
1424 |
|
1425 | let singleton = this.getOption(specifier, 'singleton');
|
1426 | if (singleton) {
|
1427 | let Class = entry;
|
1428 | assert(typeof Class === 'function', strings_1.default.ContainerEntryNotAConstructor(specifier, Class));
|
1429 | return new Class();
|
1430 | }
|
1431 | return entry;
|
1432 | }
|
1433 | |
1434 |
|
1435 |
|
1436 |
|
1437 |
|
1438 |
|
1439 | lookupRaw(specifier) {
|
1440 |
|
1441 | let entry = this.registry[specifier];
|
1442 |
|
1443 | if (!entry) {
|
1444 | lodash_1.forEach(this.resolvers, (resolver) => {
|
1445 | entry = resolver.retrieve(specifier);
|
1446 | if (entry) {
|
1447 | return false;
|
1448 | }
|
1449 | });
|
1450 | }
|
1451 | return entry == null ? false : entry;
|
1452 | }
|
1453 | |
1454 |
|
1455 |
|
1456 |
|
1457 |
|
1458 |
|
1459 |
|
1460 |
|
1461 | lookupAll(type) {
|
1462 | let entries = this.availableForType(type);
|
1463 | let values = entries.map((entry) => this.lookup(`${type}:${entry}`));
|
1464 | return lodash_1.zipObject(entries, values);
|
1465 | }
|
1466 | |
1467 |
|
1468 |
|
1469 |
|
1470 |
|
1471 | availableForType(type) {
|
1472 | let registrations = Object.keys(this.registry).filter((specifier) => {
|
1473 | return specifier.startsWith(type);
|
1474 | });
|
1475 | let resolved = this.resolvers.reverse().reduce((entries, resolver) => {
|
1476 | return entries.concat(resolver.availableForType(type));
|
1477 | }, []);
|
1478 | return lodash_1.uniq(registrations.concat(resolved)).map((specifier) => specifier.split(':')[1]);
|
1479 | }
|
1480 | |
1481 |
|
1482 |
|
1483 |
|
1484 |
|
1485 |
|
1486 | getOption(specifier, optionName) {
|
1487 | let [type] = specifier.split(':');
|
1488 | let options = lodash_1.defaults(this.options[specifier], this.options[type], DEFAULT_OPTIONS);
|
1489 | return options[optionName];
|
1490 | }
|
1491 | |
1492 |
|
1493 |
|
1494 |
|
1495 |
|
1496 | setOption(specifier, optionName, value) {
|
1497 | if (!this.options[specifier]) {
|
1498 | this.options[specifier] = Object.assign({}, DEFAULT_OPTIONS);
|
1499 | }
|
1500 | this.options[specifier][optionName] = value;
|
1501 | }
|
1502 | |
1503 |
|
1504 |
|
1505 |
|
1506 |
|
1507 | clearCache(specifier) {
|
1508 | delete this.lookups[specifier];
|
1509 | }
|
1510 | |
1511 |
|
1512 |
|
1513 |
|
1514 |
|
1515 |
|
1516 | clear() {
|
1517 | this.lookups = {};
|
1518 | this.registry = {};
|
1519 | this.resolvers = [];
|
1520 | this.loader = null;
|
1521 | }
|
1522 | |
1523 |
|
1524 |
|
1525 |
|
1526 |
|
1527 |
|
1528 | teardown() {
|
1529 | lodash_1.forEach(this.lookups, (instance) => {
|
1530 | if (typeof instance.teardown === 'function') {
|
1531 | instance.teardown();
|
1532 | }
|
1533 | });
|
1534 | }
|
1535 | }
|
1536 | exports.Container = Container;
|
1537 | class ContainerEntryNotFound extends Error {
|
1538 | constructor(specifier, registry, resolvers) {
|
1539 | let message = strings_1.default.ContainerEntryNotFound(specifier, Object.keys(registry), resolvers.map((r) => r.name));
|
1540 | super(message);
|
1541 | }
|
1542 | }
|
1543 |
|
1544 |
|
1545 |
|
1546 |
|
1547 |
|
1548 |
|
1549 |
|
1550 | const container = new Container();
|
1551 | exports.default = container;
|
1552 | exports.lookup = container.lookup.bind(container);
|
1553 |
|
1554 | });
|
1555 |
|
1556 |
|
1557 |
|
1558 |
|
1559 |
|
1560 |
|
1561 | loader.add('/lib/metal/instrumentation.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
1562 |
|
1563 | "use strict";
|
1564 | Object.defineProperty(exports, "__esModule", { value: true });
|
1565 | const EventEmitter = require("events");
|
1566 | const lodash_1 = require("lodash");
|
1567 |
|
1568 |
|
1569 |
|
1570 |
|
1571 |
|
1572 |
|
1573 |
|
1574 |
|
1575 |
|
1576 |
|
1577 |
|
1578 |
|
1579 |
|
1580 |
|
1581 |
|
1582 |
|
1583 |
|
1584 |
|
1585 |
|
1586 |
|
1587 | class InstrumentationEvent {
|
1588 | constructor(eventName, data) {
|
1589 | this.eventName = eventName;
|
1590 | this.data = data;
|
1591 | this.startTime = process.hrtime();
|
1592 | }
|
1593 | |
1594 |
|
1595 |
|
1596 | static subscribe(eventName, callback) {
|
1597 | this._emitter.on(eventName, callback);
|
1598 | }
|
1599 | |
1600 |
|
1601 |
|
1602 | static unsubscribe(eventName, callback) {
|
1603 | this._emitter.removeListener(eventName, callback);
|
1604 | }
|
1605 | |
1606 |
|
1607 |
|
1608 |
|
1609 |
|
1610 |
|
1611 | static instrument(eventName, data) {
|
1612 | return new InstrumentationEvent(eventName, data);
|
1613 | }
|
1614 | |
1615 |
|
1616 |
|
1617 | static emit(eventName, event) {
|
1618 | this._emitter.emit(eventName, event);
|
1619 | }
|
1620 | |
1621 |
|
1622 |
|
1623 |
|
1624 | finish(data) {
|
1625 | this.duration = process.hrtime(this.startTime)[1];
|
1626 | this.data = lodash_1.merge({}, this.data, data);
|
1627 | InstrumentationEvent.emit(this.eventName, this);
|
1628 | }
|
1629 | }
|
1630 |
|
1631 |
|
1632 |
|
1633 | InstrumentationEvent._emitter = new EventEmitter();
|
1634 | exports.default = InstrumentationEvent;
|
1635 |
|
1636 | });
|
1637 |
|
1638 |
|
1639 |
|
1640 |
|
1641 |
|
1642 |
|
1643 | loader.add('/lib/metal/mixin.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
1644 |
|
1645 | "use strict";
|
1646 | Object.defineProperty(exports, "__esModule", { value: true });
|
1647 | const assert = require("assert");
|
1648 |
|
1649 |
|
1650 |
|
1651 |
|
1652 |
|
1653 |
|
1654 |
|
1655 |
|
1656 |
|
1657 |
|
1658 |
|
1659 |
|
1660 |
|
1661 |
|
1662 |
|
1663 |
|
1664 |
|
1665 |
|
1666 |
|
1667 |
|
1668 |
|
1669 |
|
1670 |
|
1671 |
|
1672 |
|
1673 |
|
1674 |
|
1675 |
|
1676 |
|
1677 |
|
1678 |
|
1679 |
|
1680 |
|
1681 |
|
1682 |
|
1683 |
|
1684 |
|
1685 |
|
1686 |
|
1687 | function mixin(baseClass, ...mixins) {
|
1688 | return mixins.reduce((currentBase, mixinFactory) => {
|
1689 | let appliedClass = mixinFactory._factory(currentBase, ...mixinFactory._args);
|
1690 | assert(typeof appliedClass === 'function', `Invalid mixin (${appliedClass}) - did you forget to return your mixin class from the createMixin method?`);
|
1691 | return appliedClass;
|
1692 | }, baseClass);
|
1693 | }
|
1694 | exports.default = mixin;
|
1695 |
|
1696 |
|
1697 |
|
1698 |
|
1699 |
|
1700 |
|
1701 |
|
1702 |
|
1703 |
|
1704 |
|
1705 |
|
1706 |
|
1707 |
|
1708 |
|
1709 |
|
1710 |
|
1711 |
|
1712 |
|
1713 |
|
1714 | function createMixin(mixinFactory) {
|
1715 | let cacheMixinArguments = function (...args) {
|
1716 | cacheMixinArguments._args.push(...args);
|
1717 | return cacheMixinArguments;
|
1718 | };
|
1719 | cacheMixinArguments._args = [];
|
1720 | cacheMixinArguments._factory = mixinFactory;
|
1721 | return cacheMixinArguments;
|
1722 | }
|
1723 | exports.createMixin = createMixin;
|
1724 |
|
1725 | });
|
1726 |
|
1727 |
|
1728 |
|
1729 |
|
1730 |
|
1731 |
|
1732 | loader.add('/lib/metal/object.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
1733 |
|
1734 | "use strict";
|
1735 | Object.defineProperty(exports, "__esModule", { value: true });
|
1736 | const mixin_1 = require("./mixin");
|
1737 |
|
1738 |
|
1739 |
|
1740 |
|
1741 |
|
1742 |
|
1743 |
|
1744 | class DenaliObject {
|
1745 | |
1746 |
|
1747 |
|
1748 |
|
1749 | static mixin(...mixins) {
|
1750 | return mixin_1.default(this, ...mixins);
|
1751 | }
|
1752 | |
1753 |
|
1754 |
|
1755 |
|
1756 | teardown() {
|
1757 |
|
1758 | }
|
1759 | }
|
1760 | exports.default = DenaliObject;
|
1761 |
|
1762 | });
|
1763 |
|
1764 |
|
1765 |
|
1766 |
|
1767 |
|
1768 |
|
1769 | loader.add('/lib/metal/resolver.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
1770 |
|
1771 | "use strict";
|
1772 | Object.defineProperty(exports, "__esModule", { value: true });
|
1773 | const lodash_1 = require("lodash");
|
1774 | const path = require("path");
|
1775 | const inflection_1 = require("inflection");
|
1776 | const assert = require("assert");
|
1777 | const createDebug = require("debug");
|
1778 | class Resolver {
|
1779 | constructor(loader) {
|
1780 | |
1781 |
|
1782 |
|
1783 | this.registry = new Map();
|
1784 | assert(loader, 'You must supply a loader that the resolver should use to load from');
|
1785 | this.name = loader.pkgName;
|
1786 | this.debug = createDebug(`denali:resolver:${this.name}`);
|
1787 | this.loader = loader;
|
1788 | }
|
1789 | |
1790 |
|
1791 |
|
1792 |
|
1793 |
|
1794 |
|
1795 |
|
1796 |
|
1797 |
|
1798 | register(specifier, value) {
|
1799 | assert(specifier.includes(':'), 'Container specifiers must be in "type:entry" format');
|
1800 | this.registry.set(specifier, value);
|
1801 | }
|
1802 | |
1803 |
|
1804 |
|
1805 |
|
1806 |
|
1807 |
|
1808 |
|
1809 | retrieve(specifier) {
|
1810 | assert(specifier.includes(':'), 'Container specifiers must be in "type:entry" format');
|
1811 | this.debug(`retrieving ${specifier}`);
|
1812 | let [type, entry] = specifier.split(':');
|
1813 | if (this.registry.has(specifier)) {
|
1814 | this.debug(`cache hit, returning cached value`);
|
1815 | return this.registry.get(specifier);
|
1816 | }
|
1817 | let retrieveMethod = this[`retrieve${lodash_1.upperFirst(lodash_1.camelCase(type))}`];
|
1818 | if (!retrieveMethod) {
|
1819 | retrieveMethod = this.retrieveOther;
|
1820 | }
|
1821 | this.debug(`retrieving via retrieve${lodash_1.upperFirst(lodash_1.camelCase(type))}`);
|
1822 | let result = retrieveMethod.call(this, type, entry);
|
1823 | result = result && result.default || result;
|
1824 | this.debug('retrieved %o', result);
|
1825 | return result;
|
1826 | }
|
1827 | _retrieve(type, entry, relativepath) {
|
1828 | this.debug(`attempting to retrieve ${type}:${entry} at ${relativepath} from ${this.name}`);
|
1829 | return this.loader.loadRelative('/', relativepath, lodash_1.constant(false));
|
1830 | }
|
1831 | |
1832 |
|
1833 |
|
1834 | retrieveOther(type, entry) {
|
1835 | return this._retrieve(type, entry, path.join('/app', inflection_1.pluralize(type), entry));
|
1836 | }
|
1837 | |
1838 |
|
1839 |
|
1840 | retrieveApp(type, entry) {
|
1841 | return this._retrieve(type, entry, path.join('/app', entry));
|
1842 | }
|
1843 | |
1844 |
|
1845 |
|
1846 | retrieveConfig(type, entry) {
|
1847 | return this._retrieve(type, entry, path.join('/config', entry));
|
1848 | }
|
1849 | |
1850 |
|
1851 |
|
1852 | retrieveInitializer(type, entry) {
|
1853 | return this._retrieve(type, entry, path.join('/config', 'initializers', entry));
|
1854 | }
|
1855 | |
1856 |
|
1857 |
|
1858 |
|
1859 |
|
1860 |
|
1861 | availableForType(type) {
|
1862 | let registeredForType = [];
|
1863 | this.registry.forEach((entry, specifier) => {
|
1864 | if (specifier.split(':')[0] === type) {
|
1865 | registeredForType.push(specifier);
|
1866 | }
|
1867 | });
|
1868 | let availableMethod = this[`availableFor${lodash_1.upperFirst(lodash_1.camelCase(type))}`];
|
1869 | if (!availableMethod) {
|
1870 | availableMethod = this.availableForOther;
|
1871 | }
|
1872 | let entries = availableMethod.call(this, type);
|
1873 | let resolvedEntries = entries.map((entry) => `${type}:${entry}`);
|
1874 | return lodash_1.uniq(registeredForType.sort().concat(resolvedEntries.sort()));
|
1875 | }
|
1876 | _availableForType(prefix) {
|
1877 | let matchingFactories = Array.from(this.loader.factories.keys()).filter((moduleName) => {
|
1878 | return moduleName.startsWith(prefix);
|
1879 | });
|
1880 | return matchingFactories.map((factoryPath) => factoryPath.substring(prefix.length + 1));
|
1881 | }
|
1882 | |
1883 |
|
1884 |
|
1885 | availableForOther(type) {
|
1886 | return this._availableForType(path.join('/app', inflection_1.pluralize(type)));
|
1887 | }
|
1888 | |
1889 |
|
1890 |
|
1891 | availableForApp(type, entry) {
|
1892 | return this._availableForType('/app');
|
1893 | }
|
1894 | |
1895 |
|
1896 |
|
1897 | availableForConfig(type) {
|
1898 | return this._availableForType('/config');
|
1899 | }
|
1900 | |
1901 |
|
1902 |
|
1903 | availableForInitializer(type) {
|
1904 | return this._availableForType(path.join('/config', 'initializers'));
|
1905 | }
|
1906 | }
|
1907 | exports.default = Resolver;
|
1908 |
|
1909 | });
|
1910 |
|
1911 |
|
1912 |
|
1913 |
|
1914 |
|
1915 |
|
1916 | loader.add('/lib/parse/json-api.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
1917 |
|
1918 | "use strict";
|
1919 | Object.defineProperty(exports, "__esModule", { value: true });
|
1920 | const lodash_1 = require("lodash");
|
1921 | const assert = require("assert");
|
1922 | const json_1 = require("./json");
|
1923 | const errors_1 = require("../runtime/errors");
|
1924 | const set_if_not_empty_1 = require("../utils/set-if-not-empty");
|
1925 | const inflection_1 = require("inflection");
|
1926 |
|
1927 |
|
1928 |
|
1929 |
|
1930 |
|
1931 |
|
1932 |
|
1933 |
|
1934 | class JSONAPIParser extends json_1.default {
|
1935 | constructor() {
|
1936 | super(...arguments);
|
1937 | |
1938 |
|
1939 |
|
1940 |
|
1941 | this.type = 'application/vnd.api+json';
|
1942 | }
|
1943 | async parse(request) {
|
1944 | let body = await this.bufferAndParseBody(request);
|
1945 | let result = {
|
1946 | query: request.query,
|
1947 | headers: request.headers,
|
1948 | params: request.params
|
1949 | };
|
1950 | if (!request.hasBody) {
|
1951 | return result;
|
1952 | }
|
1953 | try {
|
1954 | assert(request.getHeader('content-type') === 'application/vnd.api+json', 'Invalid content type - must have `application/vnd.api+json` as the request content type');
|
1955 | assert(body.data, 'Invalid JSON-API document (missing top level `data` object - see http://jsonapi.org/format/#document-top-level)');
|
1956 | let parseResource = this.parseResource.bind(this);
|
1957 | if (body.data) {
|
1958 | if (!lodash_1.isArray(body.data)) {
|
1959 | result.body = parseResource(body.data);
|
1960 | }
|
1961 | else {
|
1962 | result.body = body.data.map(parseResource);
|
1963 | }
|
1964 | }
|
1965 | if (body.included) {
|
1966 | result.included = body.included.map(parseResource);
|
1967 | }
|
1968 | return result;
|
1969 | }
|
1970 | catch (e) {
|
1971 | if (e.name === 'AssertionError') {
|
1972 | throw new errors_1.default.BadRequest(e.message);
|
1973 | }
|
1974 | throw e;
|
1975 | }
|
1976 | }
|
1977 | |
1978 |
|
1979 |
|
1980 |
|
1981 |
|
1982 |
|
1983 |
|
1984 | parseResource(resource) {
|
1985 | let parsedResource = {};
|
1986 | set_if_not_empty_1.default(parsedResource, 'id', this.parseId(resource.id));
|
1987 | Object.assign(parsedResource, this.parseAttributes(resource.attributes));
|
1988 | Object.assign(parsedResource, this.parseRelationships(resource.relationships));
|
1989 | return parsedResource;
|
1990 | }
|
1991 | |
1992 |
|
1993 |
|
1994 |
|
1995 |
|
1996 | parseId(id) {
|
1997 | return id;
|
1998 | }
|
1999 | |
2000 |
|
2001 |
|
2002 |
|
2003 |
|
2004 | parseType(type) {
|
2005 | return inflection_1.singularize(type);
|
2006 | }
|
2007 | |
2008 |
|
2009 |
|
2010 |
|
2011 |
|
2012 |
|
2013 | parseAttributes(attrs) {
|
2014 | return lodash_1.mapKeys(attrs, (value, key) => {
|
2015 | return lodash_1.camelCase(key);
|
2016 | });
|
2017 | }
|
2018 | |
2019 |
|
2020 |
|
2021 |
|
2022 |
|
2023 |
|
2024 | parseRelationships(relationships) {
|
2025 | return lodash_1.mapKeys(relationships, (value, key) => {
|
2026 | return lodash_1.camelCase(key);
|
2027 | });
|
2028 | }
|
2029 | }
|
2030 | exports.default = JSONAPIParser;
|
2031 |
|
2032 | });
|
2033 |
|
2034 |
|
2035 |
|
2036 |
|
2037 |
|
2038 |
|
2039 | loader.add('/lib/parse/json.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
2040 |
|
2041 | "use strict";
|
2042 | Object.defineProperty(exports, "__esModule", { value: true });
|
2043 | const parser_1 = require("./parser");
|
2044 | const body_parser_1 = require("body-parser");
|
2045 | const bluebird_1 = require("bluebird");
|
2046 |
|
2047 |
|
2048 |
|
2049 |
|
2050 |
|
2051 |
|
2052 | class JSONParser extends parser_1.default {
|
2053 | constructor() {
|
2054 | super(...arguments);
|
2055 | |
2056 |
|
2057 |
|
2058 |
|
2059 |
|
2060 |
|
2061 | this.inflate = true;
|
2062 | |
2063 |
|
2064 |
|
2065 |
|
2066 |
|
2067 |
|
2068 |
|
2069 | this.limit = '100kb';
|
2070 | |
2071 |
|
2072 |
|
2073 |
|
2074 |
|
2075 |
|
2076 | this.strict = true;
|
2077 | |
2078 |
|
2079 |
|
2080 |
|
2081 |
|
2082 |
|
2083 |
|
2084 |
|
2085 |
|
2086 |
|
2087 |
|
2088 | this.type = 'application/json';
|
2089 | }
|
2090 | async bufferAndParseBody(request) {
|
2091 | await bluebird_1.fromNode((cb) => {
|
2092 | if (!this.jsonParserMiddleware) {
|
2093 | this.jsonParserMiddleware = body_parser_1.json({
|
2094 | inflate: this.inflate,
|
2095 | limit: this.limit,
|
2096 | reviver: this.reviver,
|
2097 | strict: this.strict,
|
2098 | type: this.type,
|
2099 | verify: this.verify
|
2100 | });
|
2101 | }
|
2102 | this.jsonParserMiddleware(request.incomingMessage, {}, cb);
|
2103 | });
|
2104 | return request.incomingMessage.body;
|
2105 | }
|
2106 | async parse(request) {
|
2107 | let body = await this.bufferAndParseBody(request);
|
2108 | return {
|
2109 | body,
|
2110 | query: request.query,
|
2111 | headers: request.headers,
|
2112 | params: request.params
|
2113 | };
|
2114 | }
|
2115 | }
|
2116 | exports.default = JSONParser;
|
2117 |
|
2118 | });
|
2119 |
|
2120 |
|
2121 |
|
2122 |
|
2123 |
|
2124 |
|
2125 | loader.add('/lib/parse/parser.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
2126 |
|
2127 | "use strict";
|
2128 | Object.defineProperty(exports, "__esModule", { value: true });
|
2129 | const object_1 = require("../metal/object");
|
2130 |
|
2131 |
|
2132 |
|
2133 |
|
2134 |
|
2135 |
|
2136 |
|
2137 |
|
2138 |
|
2139 |
|
2140 |
|
2141 |
|
2142 |
|
2143 |
|
2144 |
|
2145 | class Parser extends object_1.default {
|
2146 | }
|
2147 | exports.default = Parser;
|
2148 |
|
2149 | });
|
2150 |
|
2151 |
|
2152 |
|
2153 |
|
2154 |
|
2155 |
|
2156 | loader.add('/lib/render/json-api.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
2157 |
|
2158 | "use strict";
|
2159 | Object.defineProperty(exports, "__esModule", { value: true });
|
2160 | const lodash_1 = require("lodash");
|
2161 | const assert = require("assert");
|
2162 | const path = require("path");
|
2163 | const inflection_1 = require("inflection");
|
2164 | const serializer_1 = require("./serializer");
|
2165 | const container_1 = require("../metal/container");
|
2166 | const bluebird_1 = require("bluebird");
|
2167 | const set_if_not_empty_1 = require("../utils/set-if-not-empty");
|
2168 |
|
2169 |
|
2170 |
|
2171 |
|
2172 |
|
2173 |
|
2174 |
|
2175 | class JSONAPISerializer extends serializer_1.default {
|
2176 | constructor() {
|
2177 | super(...arguments);
|
2178 | |
2179 |
|
2180 |
|
2181 |
|
2182 |
|
2183 | this.contentType = 'application/vnd.api+json';
|
2184 | }
|
2185 | |
2186 |
|
2187 |
|
2188 |
|
2189 |
|
2190 |
|
2191 | async serialize(body, action, options) {
|
2192 | let context = {
|
2193 | action,
|
2194 | body,
|
2195 | options,
|
2196 | document: {}
|
2197 | };
|
2198 | await this.renderPrimary(context);
|
2199 | await this.renderIncluded(context);
|
2200 | this.renderMeta(context);
|
2201 | this.renderLinks(context);
|
2202 | this.renderVersion(context);
|
2203 | this.dedupeIncluded(context);
|
2204 | return context.document;
|
2205 | }
|
2206 | |
2207 |
|
2208 |
|
2209 |
|
2210 |
|
2211 |
|
2212 | async renderPrimary(context) {
|
2213 | let payload = context.body;
|
2214 | if (lodash_1.isArray(payload)) {
|
2215 | await this.renderPrimaryArray(context, payload);
|
2216 | }
|
2217 | else {
|
2218 | await this.renderPrimaryObject(context, payload);
|
2219 | }
|
2220 | }
|
2221 | |
2222 |
|
2223 |
|
2224 |
|
2225 |
|
2226 |
|
2227 | async renderPrimaryObject(context, payload) {
|
2228 | if (payload instanceof Error) {
|
2229 | context.document.errors = [await this.renderError(context, payload)];
|
2230 | }
|
2231 | else {
|
2232 | context.document.data = await this.renderRecord(context, payload);
|
2233 | }
|
2234 | }
|
2235 | |
2236 |
|
2237 |
|
2238 |
|
2239 |
|
2240 |
|
2241 | async renderPrimaryArray(context, payload) {
|
2242 | if (payload[0] instanceof Error) {
|
2243 | context.document.errors = await bluebird_1.map(payload, async (error) => {
|
2244 | assert(error instanceof Error, 'You passed a mixed array of errors and models to the JSON-API serializer. The JSON-API spec does not allow for both `data` and `errors` top level objects in a response');
|
2245 | return await this.renderError(context, error);
|
2246 | });
|
2247 | }
|
2248 | else {
|
2249 | context.document.data = await bluebird_1.map(payload, async (record) => {
|
2250 | assert(!(record instanceof Error), 'You passed a mixed array of errors and models to the JSON-API serializer. The JSON-API spec does not allow for both `data` and `errors` top level objects in a response');
|
2251 | return await this.renderRecord(context, record);
|
2252 | });
|
2253 | }
|
2254 | }
|
2255 | |
2256 |
|
2257 |
|
2258 |
|
2259 |
|
2260 |
|
2261 | async renderIncluded(context) {
|
2262 | if (context.options.included) {
|
2263 | assert(lodash_1.isArray(context.options.included), 'included records must be passed in as an array');
|
2264 | context.document.included = await bluebird_1.map(context.options.included, async (includedRecord) => {
|
2265 | return await this.renderRecord(context, includedRecord);
|
2266 | });
|
2267 | }
|
2268 | }
|
2269 | |
2270 |
|
2271 |
|
2272 |
|
2273 |
|
2274 |
|
2275 | renderMeta(context) {
|
2276 | if (context.options.meta) {
|
2277 | context.document.meta = context.options.meta;
|
2278 | }
|
2279 | }
|
2280 | |
2281 |
|
2282 |
|
2283 |
|
2284 |
|
2285 |
|
2286 | renderLinks(context) {
|
2287 | if (context.options.links) {
|
2288 | context.document.links = context.options.links;
|
2289 | }
|
2290 | }
|
2291 | |
2292 |
|
2293 |
|
2294 |
|
2295 |
|
2296 | renderVersion(context) {
|
2297 | context.document.jsonapi = {
|
2298 | version: '1.0'
|
2299 | };
|
2300 | }
|
2301 | |
2302 |
|
2303 |
|
2304 |
|
2305 |
|
2306 | async renderRecord(context, record) {
|
2307 | assert(record, `Cannot serialize ${record}. You supplied ${record} instead of a Model instance.`);
|
2308 | let serializedRecord = {
|
2309 | type: inflection_1.pluralize(record.modelName),
|
2310 | id: record.id
|
2311 | };
|
2312 | assert(serializedRecord.id != null, `Attempted to serialize a record (${record}) without an id, but the JSON-API spec requires all resources to have an id.`);
|
2313 | set_if_not_empty_1.default(serializedRecord, 'attributes', this.attributesForRecord(context, record));
|
2314 | set_if_not_empty_1.default(serializedRecord, 'relationships', await this.relationshipsForRecord(context, record));
|
2315 | set_if_not_empty_1.default(serializedRecord, 'links', this.linksForRecord(context, record));
|
2316 | set_if_not_empty_1.default(serializedRecord, 'meta', this.metaForRecord(context, record));
|
2317 | return serializedRecord;
|
2318 | }
|
2319 | |
2320 |
|
2321 |
|
2322 |
|
2323 |
|
2324 |
|
2325 | attributesForRecord(context, record) {
|
2326 | let serializedAttributes = {};
|
2327 | let attributes = this.attributesToSerialize(context.action, context.options);
|
2328 | attributes.forEach((attributeName) => {
|
2329 | let key = this.serializeAttributeName(context, attributeName);
|
2330 | let rawValue = record[attributeName];
|
2331 | if (!lodash_1.isUndefined(rawValue)) {
|
2332 | let value = this.serializeAttributeValue(context, rawValue, key, record);
|
2333 | serializedAttributes[key] = value;
|
2334 | }
|
2335 | });
|
2336 | return serializedAttributes;
|
2337 | }
|
2338 | |
2339 |
|
2340 |
|
2341 |
|
2342 |
|
2343 |
|
2344 |
|
2345 | serializeAttributeName(context, name) {
|
2346 | return lodash_1.kebabCase(name);
|
2347 | }
|
2348 | |
2349 |
|
2350 |
|
2351 |
|
2352 |
|
2353 |
|
2354 |
|
2355 |
|
2356 | serializeAttributeValue(context, value, key, record) {
|
2357 | return value;
|
2358 | }
|
2359 | |
2360 |
|
2361 |
|
2362 |
|
2363 |
|
2364 |
|
2365 | async relationshipsForRecord(context, record) {
|
2366 | let serializedRelationships = {};
|
2367 | let relationships = this.relationshipsToSerialize(context.action, context.options);
|
2368 |
|
2369 |
|
2370 | let relationshipNames = Object.keys(relationships);
|
2371 | for (let name of relationshipNames) {
|
2372 | let config = relationships[name];
|
2373 | let key = config.key || this.serializeRelationshipName(context, name);
|
2374 | let descriptor = record.constructor.schema[name];
|
2375 | assert(descriptor, `You specified a '${name}' relationship in your ${record.modelName} serializer, but no such relationship is defined on the ${record.modelName} model`);
|
2376 | serializedRelationships[key] = await this.serializeRelationship(context, name, config, descriptor, record);
|
2377 | }
|
2378 | return serializedRelationships;
|
2379 | }
|
2380 | |
2381 |
|
2382 |
|
2383 |
|
2384 |
|
2385 |
|
2386 | serializeRelationshipName(context, name) {
|
2387 | return lodash_1.kebabCase(name);
|
2388 | }
|
2389 | |
2390 |
|
2391 |
|
2392 |
|
2393 |
|
2394 |
|
2395 |
|
2396 | async serializeRelationship(context, name, config, descriptor, record) {
|
2397 | let relationship = {};
|
2398 | set_if_not_empty_1.default(relationship, 'links', this.linksForRelationship(context, name, config, descriptor, record));
|
2399 | set_if_not_empty_1.default(relationship, 'meta', this.metaForRelationship(context, name, config, descriptor, record));
|
2400 | set_if_not_empty_1.default(relationship, 'data', await this.dataForRelationship(context, name, config, descriptor, record));
|
2401 | return relationship;
|
2402 | }
|
2403 | |
2404 |
|
2405 |
|
2406 |
|
2407 |
|
2408 |
|
2409 | async dataForRelationship(context, name, config, descriptor, record) {
|
2410 | let relatedData = await record.getRelated(name);
|
2411 | if (descriptor.mode === 'hasMany') {
|
2412 | return await bluebird_1.map(relatedData, async (relatedRecord) => {
|
2413 | return await this.dataForRelatedRecord(context, name, relatedRecord, config, descriptor, record);
|
2414 | });
|
2415 | }
|
2416 | return await this.dataForRelatedRecord(context, name, relatedData, config, descriptor, record);
|
2417 | }
|
2418 | |
2419 |
|
2420 |
|
2421 |
|
2422 |
|
2423 |
|
2424 | async dataForRelatedRecord(context, name, relatedRecord, config, descriptor, record) {
|
2425 | await this.includeRecord(context, name, relatedRecord, config, descriptor);
|
2426 | return {
|
2427 | type: inflection_1.pluralize(relatedRecord.modelName),
|
2428 | id: relatedRecord.id
|
2429 | };
|
2430 | }
|
2431 | |
2432 |
|
2433 |
|
2434 |
|
2435 |
|
2436 |
|
2437 | linksForRelationship(context, name, config, descriptor, record) {
|
2438 | let recordLinks = this.linksForRecord(context, record);
|
2439 | let recordURL;
|
2440 | if (recordLinks) {
|
2441 | if (typeof recordLinks.self === 'string') {
|
2442 | recordURL = recordLinks.self;
|
2443 | }
|
2444 | else {
|
2445 | recordURL = recordLinks.self.href;
|
2446 | }
|
2447 | return {
|
2448 | self: path.join(recordURL, `relationships/${name}`),
|
2449 | related: path.join(recordURL, name)
|
2450 | };
|
2451 | }
|
2452 | return null;
|
2453 | }
|
2454 | |
2455 |
|
2456 |
|
2457 |
|
2458 |
|
2459 |
|
2460 | metaForRelationship(context, name, config, descriptor, record) {
|
2461 |
|
2462 | }
|
2463 | |
2464 |
|
2465 |
|
2466 |
|
2467 |
|
2468 |
|
2469 |
|
2470 | linksForRecord(context, record) {
|
2471 | let router = container_1.lookup('app:router');
|
2472 | let url = router.urlFor(`${inflection_1.pluralize(record.modelName)}/show`, record);
|
2473 | return typeof url === 'string' ? { self: url } : null;
|
2474 | }
|
2475 | |
2476 |
|
2477 |
|
2478 |
|
2479 |
|
2480 | metaForRecord(context, record) {
|
2481 |
|
2482 | }
|
2483 | |
2484 |
|
2485 |
|
2486 |
|
2487 |
|
2488 | async includeRecord(context, name, relatedRecord, config, descriptor) {
|
2489 | assert(relatedRecord, 'You tried to sideload an included record, but the record itself was not provided.');
|
2490 | if (!lodash_1.isArray(context.document.included)) {
|
2491 | context.document.included = [];
|
2492 | }
|
2493 | let relatedOptions = (context.options.relationships && context.options.relationships[name]) || context.options;
|
2494 | let relatedSerializer = container_1.lookup(`serializer:${config.serializer || relatedRecord.modelName}`);
|
2495 | let relatedContext = lodash_1.assign({}, context, { options: relatedOptions });
|
2496 | context.document.included.push(await relatedSerializer.renderRecord(relatedContext, relatedRecord));
|
2497 | }
|
2498 | |
2499 |
|
2500 |
|
2501 |
|
2502 |
|
2503 | renderError(context, error) {
|
2504 | let renderedError = {
|
2505 | status: String(error.status) || '500',
|
2506 | code: error.code || error.name || 'InternalServerError',
|
2507 | detail: error.message
|
2508 | };
|
2509 | set_if_not_empty_1.default(renderedError, 'id', this.idForError(context, error));
|
2510 | set_if_not_empty_1.default(renderedError, 'title', this.titleForError(context, error));
|
2511 | set_if_not_empty_1.default(renderedError, 'source', this.sourceForError(context, error));
|
2512 | set_if_not_empty_1.default(renderedError, 'meta', this.metaForError(context, error));
|
2513 | set_if_not_empty_1.default(renderedError, 'links', this.linksForError(context, error));
|
2514 | return renderedError;
|
2515 | }
|
2516 | |
2517 |
|
2518 |
|
2519 |
|
2520 |
|
2521 |
|
2522 | idForError(context, error) {
|
2523 | return error.id;
|
2524 | }
|
2525 | |
2526 |
|
2527 |
|
2528 |
|
2529 |
|
2530 |
|
2531 |
|
2532 | titleForError(context, error) {
|
2533 | return error.title;
|
2534 | }
|
2535 | |
2536 |
|
2537 |
|
2538 |
|
2539 |
|
2540 |
|
2541 | sourceForError(context, error) {
|
2542 | return error.source;
|
2543 | }
|
2544 | |
2545 |
|
2546 |
|
2547 |
|
2548 |
|
2549 |
|
2550 | metaForError(context, error) {
|
2551 | return error.meta;
|
2552 | }
|
2553 | |
2554 |
|
2555 |
|
2556 |
|
2557 |
|
2558 |
|
2559 | linksForError(context, error) {
|
2560 |
|
2561 | }
|
2562 | |
2563 |
|
2564 |
|
2565 |
|
2566 |
|
2567 | dedupeIncluded(context) {
|
2568 | if (lodash_1.isArray(context.document.included)) {
|
2569 | context.document.included = lodash_1.uniqBy(context.document.included, (resource) => {
|
2570 | return `${resource.type}/${resource.id}`;
|
2571 | });
|
2572 | }
|
2573 | }
|
2574 | }
|
2575 | exports.default = JSONAPISerializer;
|
2576 |
|
2577 | });
|
2578 |
|
2579 |
|
2580 |
|
2581 |
|
2582 |
|
2583 |
|
2584 | loader.add('/lib/render/json.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
2585 |
|
2586 | "use strict";
|
2587 | Object.defineProperty(exports, "__esModule", { value: true });
|
2588 | const lodash_1 = require("lodash");
|
2589 | const assert = require("assert");
|
2590 | const bluebird_1 = require("bluebird");
|
2591 | const serializer_1 = require("./serializer");
|
2592 | const model_1 = require("../data/model");
|
2593 | const container_1 = require("../metal/container");
|
2594 |
|
2595 |
|
2596 |
|
2597 |
|
2598 |
|
2599 |
|
2600 |
|
2601 | class JSONSerializer extends serializer_1.default {
|
2602 | constructor() {
|
2603 | super(...arguments);
|
2604 | |
2605 |
|
2606 |
|
2607 |
|
2608 |
|
2609 |
|
2610 | this.contentType = 'application/json';
|
2611 | }
|
2612 | |
2613 |
|
2614 |
|
2615 |
|
2616 |
|
2617 | async serialize(body, action, options = {}) {
|
2618 | if (body instanceof Error) {
|
2619 | return this.renderError(body, action, options);
|
2620 | }
|
2621 | return this.renderPrimary(body, action, options);
|
2622 | }
|
2623 | |
2624 |
|
2625 |
|
2626 |
|
2627 |
|
2628 | async renderPrimary(payload, action, options) {
|
2629 | if (lodash_1.isArray(payload)) {
|
2630 | return await bluebird_1.all(payload.map(async (item) => {
|
2631 | return await this.renderItem(item, action, options);
|
2632 | }));
|
2633 | }
|
2634 | return await this.renderItem(payload, action, options);
|
2635 | }
|
2636 | |
2637 |
|
2638 |
|
2639 |
|
2640 |
|
2641 | async renderItem(item, action, options) {
|
2642 | if (item instanceof model_1.default) {
|
2643 | return await this.renderModel(item, action, options);
|
2644 | }
|
2645 | return item;
|
2646 | }
|
2647 | |
2648 |
|
2649 |
|
2650 |
|
2651 |
|
2652 | async renderModel(model, action, options) {
|
2653 | let id = model.id;
|
2654 | let attributes = this.serializeAttributes(model, action, options);
|
2655 | let relationships = await this.serializeRelationships(model, action, options);
|
2656 | return lodash_1.assign({ id }, attributes, relationships);
|
2657 | }
|
2658 | |
2659 |
|
2660 |
|
2661 |
|
2662 |
|
2663 | serializeAttributes(model, action, options) {
|
2664 | let serializedAttributes = {};
|
2665 | let attributes = this.attributesToSerialize(action, options);
|
2666 | attributes.forEach((attributeName) => {
|
2667 | let key = this.serializeAttributeName(attributeName);
|
2668 | let rawValue = model[attributeName];
|
2669 | if (!lodash_1.isUndefined(rawValue)) {
|
2670 | let value = this.serializeAttributeValue(rawValue, key, model);
|
2671 | serializedAttributes[key] = value;
|
2672 | }
|
2673 | });
|
2674 | return serializedAttributes;
|
2675 | }
|
2676 | |
2677 |
|
2678 |
|
2679 |
|
2680 |
|
2681 |
|
2682 | serializeAttributeName(attributeName) {
|
2683 | return attributeName;
|
2684 | }
|
2685 | |
2686 |
|
2687 |
|
2688 |
|
2689 |
|
2690 |
|
2691 |
|
2692 |
|
2693 | serializeAttributeValue(value, key, model) {
|
2694 | return value;
|
2695 | }
|
2696 | |
2697 |
|
2698 |
|
2699 |
|
2700 |
|
2701 | async serializeRelationships(model, action, options) {
|
2702 | let serializedRelationships = {};
|
2703 | let relationships = this.relationshipsToSerialize(action, options);
|
2704 |
|
2705 |
|
2706 | for (let relationshipName in this.relationships) {
|
2707 | let config = relationships[relationshipName];
|
2708 | let key = config.key || this.serializeRelationshipName(relationshipName);
|
2709 | let descriptor = model.constructor.schema[relationshipName];
|
2710 | assert(descriptor, `You specified a '${relationshipName}' relationship in your ${this.constructor.name} serializer, but no such relationship is defined on the ${model.modelName} model`);
|
2711 | serializedRelationships[key] = await this.serializeRelationship(relationshipName, config, descriptor, model, action, options);
|
2712 | }
|
2713 | return serializedRelationships;
|
2714 | }
|
2715 | |
2716 |
|
2717 |
|
2718 |
|
2719 |
|
2720 | async serializeRelationship(relationship, config, descriptor, model, action, options) {
|
2721 | let relatedSerializer = container_1.lookup(`serializer:${descriptor.relatedModelName}`, { loose: true }) || container_1.lookup(`serializer:application`, { loose: true });
|
2722 | if (typeof relatedSerializer === 'boolean') {
|
2723 | throw new Error(`No serializer found for ${descriptor.relatedModelName}, and no fallback application serializer found either`);
|
2724 | }
|
2725 | if (descriptor.mode === 'hasMany') {
|
2726 | let relatedModels = await model.getRelated(relationship);
|
2727 | return await bluebird_1.all(relatedModels.map(async (relatedModel) => {
|
2728 | if (config.strategy === 'embed') {
|
2729 | return await relatedSerializer.renderModel(relatedModel, action, options);
|
2730 | }
|
2731 | else if (config.strategy === 'id') {
|
2732 | return relatedModel.id;
|
2733 | }
|
2734 | }));
|
2735 | }
|
2736 | else {
|
2737 | let relatedModel = await model.getRelated(relationship);
|
2738 | if (config.strategy === 'embed') {
|
2739 | return await relatedSerializer.renderModel(relatedModel, action, options);
|
2740 | }
|
2741 | else if (config.strategy === 'id') {
|
2742 | return relatedModel.id;
|
2743 | }
|
2744 | }
|
2745 | }
|
2746 | |
2747 |
|
2748 |
|
2749 |
|
2750 |
|
2751 |
|
2752 | serializeRelationshipName(name) {
|
2753 | return name;
|
2754 | }
|
2755 | |
2756 |
|
2757 |
|
2758 |
|
2759 |
|
2760 | renderError(error, action, options) {
|
2761 | return {
|
2762 | status: error.status || 500,
|
2763 | code: error.code || 'InternalServerError',
|
2764 | message: error.message
|
2765 | };
|
2766 | }
|
2767 | }
|
2768 | exports.default = JSONSerializer;
|
2769 |
|
2770 | });
|
2771 |
|
2772 |
|
2773 |
|
2774 |
|
2775 |
|
2776 |
|
2777 | loader.add('/lib/render/serializer.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
2778 |
|
2779 | "use strict";
|
2780 | Object.defineProperty(exports, "__esModule", { value: true });
|
2781 | const view_1 = require("./view");
|
2782 | const errors_1 = require("../runtime/errors");
|
2783 | const result_1 = require("../utils/result");
|
2784 | const container_1 = require("../metal/container");
|
2785 |
|
2786 |
|
2787 |
|
2788 |
|
2789 |
|
2790 |
|
2791 |
|
2792 |
|
2793 | class Serializer extends view_1.default {
|
2794 | constructor() {
|
2795 | super(...arguments);
|
2796 | |
2797 |
|
2798 |
|
2799 |
|
2800 |
|
2801 | this.contentType = 'application/json';
|
2802 | }
|
2803 | |
2804 |
|
2805 |
|
2806 |
|
2807 |
|
2808 |
|
2809 |
|
2810 | attributesToSerialize(action, options) {
|
2811 | return options.attributes || result_1.default(this.attributes, action);
|
2812 | }
|
2813 | |
2814 |
|
2815 |
|
2816 |
|
2817 |
|
2818 |
|
2819 |
|
2820 | relationshipsToSerialize(action, options) {
|
2821 | return options.relationships || result_1.default(this.relationships, action);
|
2822 | }
|
2823 | async render(action, response, body, options) {
|
2824 | response.setHeader('Content-type', this.contentType);
|
2825 | if (body instanceof errors_1.default) {
|
2826 | response.statusCode = body.status;
|
2827 | }
|
2828 | body = await this.serialize(body, action, options);
|
2829 | let isProduction = container_1.lookup('config:environment').environment === 'production';
|
2830 | response.write(JSON.stringify(body, null, isProduction ? 0 : 2) || '');
|
2831 | response.end();
|
2832 | }
|
2833 | }
|
2834 | exports.default = Serializer;
|
2835 |
|
2836 | });
|
2837 |
|
2838 |
|
2839 |
|
2840 |
|
2841 |
|
2842 |
|
2843 | loader.add('/lib/render/view.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
2844 |
|
2845 | "use strict";
|
2846 | Object.defineProperty(exports, "__esModule", { value: true });
|
2847 | const object_1 = require("../metal/object");
|
2848 | class View extends object_1.default {
|
2849 | }
|
2850 | exports.default = View;
|
2851 |
|
2852 | });
|
2853 |
|
2854 |
|
2855 |
|
2856 |
|
2857 |
|
2858 |
|
2859 | loader.add('/lib/runtime/action.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
2860 |
|
2861 | "use strict";
|
2862 | Object.defineProperty(exports, "__esModule", { value: true });
|
2863 | const lodash_1 = require("lodash");
|
2864 | const protochain = require("protochain");
|
2865 | const instrumentation_1 = require("../metal/instrumentation");
|
2866 | const model_1 = require("../data/model");
|
2867 | const createDebug = require("debug");
|
2868 | const assert = require("assert");
|
2869 | const object_1 = require("../metal/object");
|
2870 | const errors_1 = require("./errors");
|
2871 | const container_1 = require("../metal/container");
|
2872 | const debug = createDebug('denali:action');
|
2873 | const beforeFiltersCache = new Map();
|
2874 | const afterFiltersCache = new Map();
|
2875 |
|
2876 |
|
2877 |
|
2878 |
|
2879 |
|
2880 |
|
2881 |
|
2882 |
|
2883 |
|
2884 |
|
2885 |
|
2886 |
|
2887 |
|
2888 |
|
2889 |
|
2890 |
|
2891 |
|
2892 |
|
2893 |
|
2894 | class Action extends object_1.default {
|
2895 | constructor() {
|
2896 | super(...arguments);
|
2897 | |
2898 |
|
2899 |
|
2900 |
|
2901 |
|
2902 | this.config = container_1.lookup('service:config');
|
2903 | |
2904 |
|
2905 |
|
2906 |
|
2907 |
|
2908 |
|
2909 |
|
2910 |
|
2911 | this.parser = container_1.lookup('parser:application');
|
2912 | |
2913 |
|
2914 |
|
2915 |
|
2916 |
|
2917 | this.logger = container_1.lookup('app:logger');
|
2918 | |
2919 |
|
2920 |
|
2921 | this.hasRendered = false;
|
2922 | }
|
2923 | async render(status, body, options) {
|
2924 | if (typeof status !== 'number') {
|
2925 | options = body;
|
2926 | body = status;
|
2927 | status = 200;
|
2928 | }
|
2929 | if (!options) {
|
2930 | options = {};
|
2931 | }
|
2932 | this.hasRendered = true;
|
2933 | debug(`[${this.request.id}]: rendering`);
|
2934 | this.response.setHeader('X-Request-Id', this.request.id);
|
2935 | debug(`[${this.request.id}]: setting response status code to ${status}`);
|
2936 | this.response.statusCode = status;
|
2937 | if (!body) {
|
2938 | debug(`[${this.request.id}]: no response body to render, response finished`);
|
2939 | this.response.end();
|
2940 | return;
|
2941 | }
|
2942 |
|
2943 | if (options.view) {
|
2944 | let view = container_1.lookup(`view:${options.view}`);
|
2945 | assert(view, `No such view: ${options.view}`);
|
2946 | debug(`[${this.request.id}]: rendering response body with the ${options.view} view`);
|
2947 | return await view.render(this, this.response, body, options);
|
2948 | }
|
2949 |
|
2950 | let serializerLookup = 'application';
|
2951 | if (options.serializer) {
|
2952 | serializerLookup = options.serializer;
|
2953 | }
|
2954 | else {
|
2955 | let sample = lodash_1.isArray(body) ? body[0] : body;
|
2956 | if (sample instanceof model_1.default) {
|
2957 | serializerLookup = sample.modelName;
|
2958 | }
|
2959 | }
|
2960 |
|
2961 | let serializer = container_1.lookup(`serializer:${serializerLookup}`);
|
2962 | debug(`[${this.request.id}]: rendering response body with the ${serializerLookup} serializer`);
|
2963 | return await serializer.render(this, this.response, body, options);
|
2964 | }
|
2965 | |
2966 |
|
2967 |
|
2968 |
|
2969 |
|
2970 |
|
2971 |
|
2972 |
|
2973 |
|
2974 |
|
2975 | async run(request, response) {
|
2976 | this.request = request;
|
2977 | this.response = response;
|
2978 |
|
2979 | debug(`[${request.id}]: parsing request`);
|
2980 | assert(typeof this.parser.parse === 'function', 'The parser you supply must define a `parse(request)` method. See the parser docs for details');
|
2981 | let parsedRequest = await this.parser.parse(request);
|
2982 |
|
2983 | let { beforeChain, afterChain } = this._buildFilterChains();
|
2984 | let instrumentation = instrumentation_1.default.instrument('action.run', {
|
2985 | action: this.actionPath,
|
2986 | parsed: parsedRequest
|
2987 | });
|
2988 |
|
2989 | debug(`[${this.request.id}]: running before filters`);
|
2990 | await this._invokeFilters(beforeChain, parsedRequest);
|
2991 |
|
2992 | if (!this.hasRendered) {
|
2993 | debug(`[${this.request.id}]: running responder`);
|
2994 | let result = await this.respond(parsedRequest);
|
2995 |
|
2996 | if (!this.hasRendered) {
|
2997 | debug(`[${this.request.id}]: autorendering`);
|
2998 | await this.render(result);
|
2999 | }
|
3000 | }
|
3001 |
|
3002 | debug(`[${this.request.id}]: running after filters`);
|
3003 | await this._invokeFilters(afterChain, parsedRequest);
|
3004 |
|
3005 | if (!this.hasRendered) {
|
3006 | throw new errors_1.default.InternalServerError(`${this.actionPath} did not render anything`);
|
3007 | }
|
3008 | instrumentation.finish();
|
3009 | }
|
3010 | |
3011 |
|
3012 |
|
3013 | async _invokeFilters(chain, parsedRequest) {
|
3014 | chain = lodash_1.clone(chain);
|
3015 | while (chain.length > 0) {
|
3016 | let filter = chain.shift();
|
3017 | let instrumentation = instrumentation_1.default.instrument('action.filter', {
|
3018 | action: this.actionPath,
|
3019 | request: parsedRequest,
|
3020 | filter: filter.name
|
3021 | });
|
3022 | debug(`[${this.request.id}]: running '${filter.name}' filter`);
|
3023 | let filterResult = await filter.call(this, parsedRequest);
|
3024 | instrumentation.finish();
|
3025 | if (!this.hasRendered && filterResult) {
|
3026 | return this.render(200, filterResult);
|
3027 | }
|
3028 | }
|
3029 | }
|
3030 | |
3031 |
|
3032 |
|
3033 |
|
3034 |
|
3035 |
|
3036 |
|
3037 |
|
3038 |
|
3039 | _buildFilterChains() {
|
3040 | let ActionClass = this.constructor;
|
3041 | if (!beforeFiltersCache.has(ActionClass)) {
|
3042 | let prototypeChain = protochain(ActionClass).reverse().concat(ActionClass);
|
3043 | this._buildFilterChain('before', beforeFiltersCache, prototypeChain);
|
3044 | this._buildFilterChain('after', afterFiltersCache, prototypeChain);
|
3045 | }
|
3046 | return {
|
3047 | beforeChain: beforeFiltersCache.get(ActionClass),
|
3048 | afterChain: afterFiltersCache.get(ActionClass)
|
3049 | };
|
3050 | }
|
3051 | _buildFilterChain(stageName, cache, prototypes) {
|
3052 | let ActionClass = this.constructor;
|
3053 | let compiledFilterList = lodash_1.flatMap(prototypes, (prototype) => {
|
3054 | let filters = lodash_1.get(prototype, stageName, []);
|
3055 | filters = lodash_1.castArray(filters);
|
3056 | return filters.map((filter) => {
|
3057 | if (typeof filter === 'string') {
|
3058 | assert(typeof lodash_1.get(this, filter) === 'function', `${filter} method not found on the ${this.actionPath} action.`);
|
3059 | return this[filter];
|
3060 | }
|
3061 | return filter;
|
3062 | });
|
3063 | });
|
3064 | cache.set(ActionClass, compiledFilterList);
|
3065 | }
|
3066 | }
|
3067 |
|
3068 |
|
3069 |
|
3070 |
|
3071 |
|
3072 |
|
3073 |
|
3074 |
|
3075 |
|
3076 |
|
3077 |
|
3078 |
|
3079 |
|
3080 |
|
3081 |
|
3082 |
|
3083 |
|
3084 |
|
3085 |
|
3086 | Action.before = [];
|
3087 |
|
3088 |
|
3089 |
|
3090 |
|
3091 |
|
3092 |
|
3093 |
|
3094 |
|
3095 |
|
3096 |
|
3097 |
|
3098 |
|
3099 |
|
3100 |
|
3101 | Action.after = [];
|
3102 | exports.default = Action;
|
3103 |
|
3104 | });
|
3105 |
|
3106 |
|
3107 |
|
3108 |
|
3109 |
|
3110 |
|
3111 | loader.add('/lib/runtime/addon.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3112 |
|
3113 | "use strict";
|
3114 | Object.defineProperty(exports, "__esModule", { value: true });
|
3115 | const container_1 = require("../metal/container");
|
3116 |
|
3117 |
|
3118 |
|
3119 |
|
3120 |
|
3121 |
|
3122 |
|
3123 |
|
3124 | class Addon {
|
3125 | |
3126 |
|
3127 |
|
3128 | get resolver() {
|
3129 | return this.loader.resolver;
|
3130 | }
|
3131 | constructor(loader, options) {
|
3132 | this.loader = loader;
|
3133 | this.environment = options.environment;
|
3134 | container_1.default.register(`addon:${this.name}`, this);
|
3135 | }
|
3136 | |
3137 |
|
3138 |
|
3139 |
|
3140 |
|
3141 |
|
3142 | get name() {
|
3143 | return `${this.loader.pkgName}@${this.loader.version}`;
|
3144 | }
|
3145 | |
3146 |
|
3147 |
|
3148 |
|
3149 |
|
3150 |
|
3151 | async shutdown(application) {
|
3152 |
|
3153 | }
|
3154 | }
|
3155 | exports.default = Addon;
|
3156 |
|
3157 | });
|
3158 |
|
3159 |
|
3160 |
|
3161 |
|
3162 |
|
3163 |
|
3164 | loader.add('/lib/runtime/application.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3165 |
|
3166 | "use strict";
|
3167 | Object.defineProperty(exports, "__esModule", { value: true });
|
3168 | const lodash_1 = require("lodash");
|
3169 | const http = require("http");
|
3170 | const https = require("https");
|
3171 | const bluebird_1 = require("bluebird");
|
3172 | const addon_1 = require("./addon");
|
3173 | const topsort_1 = require("../utils/topsort");
|
3174 | const container_1 = require("../metal/container");
|
3175 |
|
3176 |
|
3177 |
|
3178 |
|
3179 |
|
3180 |
|
3181 | class Application extends addon_1.default {
|
3182 | constructor(loader, options) {
|
3183 | super(loader, lodash_1.defaults(options, { environment: 'development' }));
|
3184 | |
3185 |
|
3186 |
|
3187 |
|
3188 |
|
3189 |
|
3190 | this.addons = [];
|
3191 | this.loader.children.forEach((addonLoader, addonName) => {
|
3192 | let AddonClass = addonLoader.resolver.retrieve('app:addon') || addon_1.default;
|
3193 | this.addons.push(new AddonClass(addonLoader, options));
|
3194 | });
|
3195 | this.drainers = [];
|
3196 |
|
3197 | container_1.default.register('app:main', this);
|
3198 | this.router = container_1.default.lookup('app:router');
|
3199 | this.logger = container_1.default.lookup('app:logger');
|
3200 |
|
3201 | this.generateConfig();
|
3202 | this.config = container_1.default.lookup('service:config');
|
3203 | this.compileRouter();
|
3204 | }
|
3205 | |
3206 |
|
3207 |
|
3208 |
|
3209 |
|
3210 |
|
3211 |
|
3212 |
|
3213 |
|
3214 |
|
3215 |
|
3216 |
|
3217 |
|
3218 |
|
3219 |
|
3220 |
|
3221 | generateConfig() {
|
3222 | let appConfig = this.resolver.retrieve('config:environment') || lodash_1.constant({
|
3223 | environment: 'development',
|
3224 | server: {
|
3225 | port: 3000
|
3226 | }
|
3227 | });
|
3228 | let config = appConfig(this.environment, container_1.default);
|
3229 | config.environment = this.environment;
|
3230 | container_1.default.register('config:environment', config);
|
3231 | this.addons.forEach((addon) => {
|
3232 | let addonConfig = addon.resolver.retrieve('config:environment');
|
3233 | if (addonConfig) {
|
3234 | addonConfig(this.environment, container_1.default, config);
|
3235 | }
|
3236 | });
|
3237 | return config;
|
3238 | }
|
3239 | |
3240 |
|
3241 |
|
3242 | compileRouter() {
|
3243 |
|
3244 | this.addons.forEach((addon) => {
|
3245 | let addonMiddleware = addon.resolver.retrieve('config:middleware') || lodash_1.noop;
|
3246 | addonMiddleware(this.router, this);
|
3247 | });
|
3248 |
|
3249 | let appMiddleware = this.resolver.retrieve('config:middleware') || lodash_1.noop;
|
3250 | appMiddleware(this.router, this);
|
3251 |
|
3252 | let appRoutes = this.resolver.retrieve('config:routes') || lodash_1.noop;
|
3253 | appRoutes(this.router, this);
|
3254 |
|
3255 | this.addons.reverse().forEach((addon) => {
|
3256 | let addonRoutes = addon.resolver.retrieve('config:routes') || lodash_1.noop;
|
3257 | addonRoutes(this.router, this);
|
3258 | });
|
3259 | }
|
3260 | |
3261 |
|
3262 |
|
3263 |
|
3264 |
|
3265 |
|
3266 | async start() {
|
3267 | let port = this.config.getWithDefault('server', 'port', 3000);
|
3268 | await this.runInitializers();
|
3269 | if (!this.config.get('server', 'detached')) {
|
3270 | await this.createServer(port);
|
3271 | this.logger.info(`${this.name} server up on port ${port}`);
|
3272 | }
|
3273 | }
|
3274 | |
3275 |
|
3276 |
|
3277 |
|
3278 | async createServer(port) {
|
3279 | await new Promise((resolve) => {
|
3280 | let handler = this.router.handle.bind(this.router);
|
3281 | let server;
|
3282 | if (this.config.get('server', 'ssl')) {
|
3283 | server = https.createServer(this.config.get('server', 'ssl'), handler).listen(port, resolve);
|
3284 | }
|
3285 | else {
|
3286 | server = http.createServer(handler).listen(port, resolve);
|
3287 | }
|
3288 | this.drainers.push(async function drainHttp() {
|
3289 | await new Promise((resolveDrainer) => {
|
3290 | server.close(resolveDrainer);
|
3291 | setTimeout(resolveDrainer, 60 * 1000);
|
3292 | });
|
3293 | });
|
3294 | });
|
3295 | }
|
3296 | |
3297 |
|
3298 |
|
3299 |
|
3300 |
|
3301 |
|
3302 |
|
3303 |
|
3304 | async runInitializers() {
|
3305 | let initializers = lodash_1.values(container_1.default.lookupAll('initializer'));
|
3306 | initializers = topsort_1.default(initializers);
|
3307 | for (let initializer of initializers) {
|
3308 | await initializer.initialize(this);
|
3309 | }
|
3310 | }
|
3311 | |
3312 |
|
3313 |
|
3314 |
|
3315 |
|
3316 |
|
3317 | async shutdown() {
|
3318 | await bluebird_1.all(this.drainers.map((drainer) => drainer()));
|
3319 | await bluebird_1.all(this.addons.map(async (addon) => {
|
3320 | await addon.shutdown(this);
|
3321 | }));
|
3322 | container_1.default.teardown();
|
3323 | }
|
3324 | }
|
3325 | exports.default = Application;
|
3326 |
|
3327 | });
|
3328 |
|
3329 |
|
3330 |
|
3331 |
|
3332 |
|
3333 |
|
3334 | loader.add('/lib/runtime/config.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3335 |
|
3336 | "use strict";
|
3337 | Object.defineProperty(exports, "__esModule", { value: true });
|
3338 | const service_1 = require("./service");
|
3339 | const lodash_1 = require("lodash");
|
3340 | const container_1 = require("../metal/container");
|
3341 | class ConfigService extends service_1.default {
|
3342 | constructor() {
|
3343 | super(...arguments);
|
3344 | this._config = container_1.lookup('config:environment');
|
3345 | }
|
3346 | get environment() {
|
3347 | return this._config.environment;
|
3348 | }
|
3349 | get(...path) {
|
3350 |
|
3351 | path = path.reduce((segments, nextSegment) => segments.concat(nextSegment.split('.')), []);
|
3352 | return lodash_1.get(this._config, path);
|
3353 | }
|
3354 | getWithDefault(...args) {
|
3355 | let defaultValue = args.pop();
|
3356 | let path = args;
|
3357 |
|
3358 | path = path.reduce((segments, nextSegment) => segments.concat(nextSegment.split('.')), []);
|
3359 | return lodash_1.get(this._config, path, defaultValue);
|
3360 | }
|
3361 | }
|
3362 | exports.default = ConfigService;
|
3363 |
|
3364 | });
|
3365 |
|
3366 |
|
3367 |
|
3368 |
|
3369 |
|
3370 |
|
3371 | loader.add('/lib/runtime/errors.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3372 |
|
3373 | "use strict";
|
3374 | Object.defineProperty(exports, "__esModule", { value: true });
|
3375 | const Errors = require("http-errors");
|
3376 |
|
3377 |
|
3378 |
|
3379 |
|
3380 |
|
3381 |
|
3382 |
|
3383 |
|
3384 | exports.default = Errors;
|
3385 |
|
3386 | });
|
3387 |
|
3388 |
|
3389 |
|
3390 |
|
3391 |
|
3392 |
|
3393 | loader.add('/lib/runtime/logger.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3394 |
|
3395 | "use strict";
|
3396 | Object.defineProperty(exports, "__esModule", { value: true });
|
3397 | const lodash_1 = require("lodash");
|
3398 | const chalk_1 = require("chalk");
|
3399 | const object_1 = require("../metal/object");
|
3400 |
|
3401 |
|
3402 |
|
3403 |
|
3404 |
|
3405 |
|
3406 |
|
3407 | class Logger extends object_1.default {
|
3408 | constructor() {
|
3409 | super(...arguments);
|
3410 | |
3411 |
|
3412 |
|
3413 |
|
3414 |
|
3415 | this.loglevel = 'info';
|
3416 | |
3417 |
|
3418 |
|
3419 |
|
3420 |
|
3421 | this.colorize = true;
|
3422 | |
3423 |
|
3424 |
|
3425 | this.levels = [
|
3426 | 'info',
|
3427 | 'warn',
|
3428 | 'error'
|
3429 | ];
|
3430 | |
3431 |
|
3432 |
|
3433 | this.colors = {
|
3434 | info: chalk_1.default.white,
|
3435 | warn: chalk_1.default.yellow,
|
3436 | error: chalk_1.default.red
|
3437 | };
|
3438 | }
|
3439 | |
3440 |
|
3441 |
|
3442 |
|
3443 |
|
3444 | info(msg) {
|
3445 | this.log('info', msg);
|
3446 | }
|
3447 | |
3448 |
|
3449 |
|
3450 |
|
3451 |
|
3452 | warn(msg) {
|
3453 | this.log('warn', msg);
|
3454 | }
|
3455 | |
3456 |
|
3457 |
|
3458 |
|
3459 |
|
3460 | error(msg) {
|
3461 | this.log('error', msg);
|
3462 | }
|
3463 | |
3464 |
|
3465 |
|
3466 | log(level, msg) {
|
3467 | if (this.levels.indexOf(level) === -1) {
|
3468 | level = this.loglevel;
|
3469 | }
|
3470 | let timestamp = (new Date()).toISOString();
|
3471 | let padLength = this.levels.reduce((n, label) => Math.max(n, label.length), null);
|
3472 | let levelLabel = lodash_1.padStart(level.toUpperCase(), padLength);
|
3473 | if (this.colorize) {
|
3474 | let colorizer = this.colors[level] || lodash_1.identity;
|
3475 | msg = colorizer(msg);
|
3476 | levelLabel = colorizer(levelLabel);
|
3477 | }
|
3478 |
|
3479 | console.log(`[${timestamp}] ${levelLabel} - ${msg}`);
|
3480 | if (level === 'error') {
|
3481 | debugger;
|
3482 | }
|
3483 |
|
3484 | }
|
3485 | }
|
3486 | exports.default = Logger;
|
3487 |
|
3488 | });
|
3489 |
|
3490 |
|
3491 |
|
3492 |
|
3493 |
|
3494 |
|
3495 | loader.add('/lib/runtime/request.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3496 |
|
3497 | "use strict";
|
3498 | Object.defineProperty(exports, "__esModule", { value: true });
|
3499 | const lodash_1 = require("lodash");
|
3500 | const accepts = require("accepts");
|
3501 | const net_1 = require("net");
|
3502 | const typeis = require("type-is");
|
3503 | const parseRange = require("range-parser");
|
3504 | const parse = require("parseurl");
|
3505 | const proxyaddr = require("proxy-addr");
|
3506 | const uuid = require("uuid");
|
3507 | const url = require("url");
|
3508 |
|
3509 |
|
3510 |
|
3511 |
|
3512 |
|
3513 |
|
3514 |
|
3515 | class Request {
|
3516 | constructor(incomingMessage, serverConfig) {
|
3517 | |
3518 |
|
3519 |
|
3520 |
|
3521 |
|
3522 |
|
3523 | this.id = uuid.v4();
|
3524 | this.incomingMessage = incomingMessage;
|
3525 | this.config = serverConfig || {};
|
3526 | }
|
3527 | |
3528 |
|
3529 |
|
3530 |
|
3531 |
|
3532 | get method() {
|
3533 | return this.incomingMessage.method.toUpperCase();
|
3534 | }
|
3535 | |
3536 |
|
3537 |
|
3538 |
|
3539 |
|
3540 | get path() {
|
3541 | return parse(this.incomingMessage).pathname;
|
3542 | }
|
3543 | |
3544 |
|
3545 |
|
3546 |
|
3547 |
|
3548 | get query() {
|
3549 | return url.parse(this.incomingMessage.url, true).query;
|
3550 | }
|
3551 | |
3552 |
|
3553 |
|
3554 |
|
3555 |
|
3556 | get headers() {
|
3557 | return this.incomingMessage.headers;
|
3558 | }
|
3559 | |
3560 |
|
3561 |
|
3562 |
|
3563 |
|
3564 |
|
3565 |
|
3566 |
|
3567 |
|
3568 |
|
3569 |
|
3570 |
|
3571 |
|
3572 |
|
3573 | get subdomains() {
|
3574 | let hostname = this.hostname;
|
3575 | if (!hostname) {
|
3576 | return [];
|
3577 | }
|
3578 | let offset = this.config.subdomainOffset;
|
3579 | let subdomains = !net_1.isIP(hostname) ? hostname.split('.').reverse() : [hostname];
|
3580 | return subdomains.slice(offset == null ? 2 : offset);
|
3581 | }
|
3582 | |
3583 |
|
3584 |
|
3585 |
|
3586 |
|
3587 |
|
3588 |
|
3589 |
|
3590 |
|
3591 |
|
3592 | get protocol() {
|
3593 | let rawProtocol = this.incomingMessage.connection.encrypted ? 'https' : 'http';
|
3594 | let ip = this.incomingMessage.connection.remoteAddress;
|
3595 | let trustProxyConfig = this.config.trustProxy || lodash_1.constant(false);
|
3596 | if (trustProxyConfig) {
|
3597 | let trustProxy;
|
3598 | if (typeof trustProxyConfig !== 'function') {
|
3599 | trustProxy = proxyaddr.compile(trustProxyConfig);
|
3600 | }
|
3601 | else {
|
3602 | trustProxy = trustProxyConfig;
|
3603 | }
|
3604 | if (trustProxy(ip, 0)) {
|
3605 | let proxyClaimedProtocol = this.getHeader('X-Forwarded-Proto') || rawProtocol;
|
3606 | return proxyClaimedProtocol.split(/\s*,\s*/)[0];
|
3607 | }
|
3608 | }
|
3609 | return rawProtocol;
|
3610 | }
|
3611 | |
3612 |
|
3613 |
|
3614 |
|
3615 |
|
3616 | get xhr() {
|
3617 | let val = this.getHeader('X-Requested-With') || '';
|
3618 | return val.toLowerCase() === 'xmlhttprequest';
|
3619 | }
|
3620 | |
3621 |
|
3622 |
|
3623 |
|
3624 |
|
3625 |
|
3626 |
|
3627 |
|
3628 | get hostname() {
|
3629 | let host = this.getHeader('X-Forwarded-Host');
|
3630 | let ip = this.incomingMessage.socket.remoteAddress;
|
3631 | let trustProxyConfig = this.config.trustProxy || lodash_1.constant(false);
|
3632 | let trustProxy;
|
3633 | if (typeof trustProxyConfig !== 'function') {
|
3634 | trustProxy = proxyaddr.compile(trustProxyConfig);
|
3635 | }
|
3636 | else {
|
3637 | trustProxy = trustProxyConfig;
|
3638 | }
|
3639 | if (!host || !trustProxy(ip, 0)) {
|
3640 | host = this.getHeader('Host');
|
3641 | }
|
3642 | if (!host) {
|
3643 | return;
|
3644 | }
|
3645 |
|
3646 | let offset = host[0] === '[' ? host.indexOf(']') + 1 : 0;
|
3647 | let index = host.indexOf(':', offset);
|
3648 | return index !== -1 ? host.substring(0, index) : host;
|
3649 | }
|
3650 | |
3651 |
|
3652 |
|
3653 |
|
3654 |
|
3655 |
|
3656 |
|
3657 | get ip() {
|
3658 | let trustProxyConfig = this.config.trustProxy || lodash_1.constant(false);
|
3659 | return proxyaddr(this.incomingMessage, trustProxyConfig);
|
3660 | }
|
3661 | |
3662 |
|
3663 |
|
3664 |
|
3665 |
|
3666 |
|
3667 |
|
3668 |
|
3669 |
|
3670 | get ips() {
|
3671 | let trustProxyConfig = this.config.trustProxy || lodash_1.constant(false);
|
3672 | let ips = proxyaddr.all(this.incomingMessage, trustProxyConfig);
|
3673 | ips.reverse().pop();
|
3674 | return ips;
|
3675 | }
|
3676 | |
3677 |
|
3678 |
|
3679 | get hasBody() {
|
3680 | return typeis.hasBody(this.incomingMessage);
|
3681 | }
|
3682 | getHeader(name) {
|
3683 | return this.incomingMessage.headers[name.toLowerCase()];
|
3684 | }
|
3685 | accepts(...type) {
|
3686 | let accept = accepts(this.incomingMessage);
|
3687 | return accept.types(...type);
|
3688 | }
|
3689 | acceptsEncodings(...encoding) {
|
3690 | let accept = accepts(this.incomingMessage);
|
3691 |
|
3692 |
|
3693 | return accept.encodings(...encoding);
|
3694 | }
|
3695 | acceptsCharsets(...charset) {
|
3696 | let accept = accepts(this.incomingMessage);
|
3697 |
|
3698 |
|
3699 | return accept.charsets(...charset);
|
3700 | }
|
3701 | acceptsLanguages(...lang) {
|
3702 | let accept = accepts(this.incomingMessage);
|
3703 |
|
3704 |
|
3705 | return accept.languages(...lang);
|
3706 | }
|
3707 | |
3708 |
|
3709 |
|
3710 |
|
3711 |
|
3712 |
|
3713 |
|
3714 |
|
3715 |
|
3716 |
|
3717 |
|
3718 |
|
3719 |
|
3720 |
|
3721 |
|
3722 |
|
3723 |
|
3724 |
|
3725 |
|
3726 |
|
3727 | range(size, options) {
|
3728 | let range = this.getHeader('Range');
|
3729 | if (!range) {
|
3730 | return;
|
3731 | }
|
3732 | return parseRange(size, range, options);
|
3733 | }
|
3734 | |
3735 |
|
3736 |
|
3737 |
|
3738 |
|
3739 |
|
3740 |
|
3741 |
|
3742 |
|
3743 |
|
3744 |
|
3745 |
|
3746 |
|
3747 |
|
3748 |
|
3749 |
|
3750 |
|
3751 |
|
3752 |
|
3753 |
|
3754 |
|
3755 |
|
3756 |
|
3757 | is(...types) {
|
3758 | if (Array.isArray(types[0])) {
|
3759 | types = types[0];
|
3760 | }
|
3761 | return typeis(this.incomingMessage, types);
|
3762 | }
|
3763 | }
|
3764 | exports.default = Request;
|
3765 |
|
3766 | });
|
3767 |
|
3768 |
|
3769 |
|
3770 |
|
3771 |
|
3772 |
|
3773 | loader.add('/lib/runtime/route.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3774 |
|
3775 | "use strict";
|
3776 | Object.defineProperty(exports, "__esModule", { value: true });
|
3777 | const RouteParser = require("route-parser");
|
3778 |
|
3779 |
|
3780 |
|
3781 |
|
3782 |
|
3783 |
|
3784 | class Route extends RouteParser {
|
3785 | }
|
3786 | exports.default = Route;
|
3787 |
|
3788 | });
|
3789 |
|
3790 |
|
3791 |
|
3792 |
|
3793 |
|
3794 |
|
3795 | loader.add('/lib/runtime/router.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
3796 |
|
3797 | "use strict";
|
3798 | Object.defineProperty(exports, "__esModule", { value: true });
|
3799 | const ware = require("ware");
|
3800 | const inflection_1 = require("inflection");
|
3801 | const bluebird_1 = require("bluebird");
|
3802 | const createDebug = require("debug");
|
3803 | const errors_1 = require("./errors");
|
3804 | const route_1 = require("./route");
|
3805 | const request_1 = require("./request");
|
3806 | const object_1 = require("../metal/object");
|
3807 | const container_1 = require("../metal/container");
|
3808 | const lodash_1 = require("lodash");
|
3809 | const debug = createDebug('denali:router');
|
3810 |
|
3811 |
|
3812 |
|
3813 |
|
3814 |
|
3815 |
|
3816 |
|
3817 |
|
3818 |
|
3819 | class Router extends object_1.default {
|
3820 | constructor() {
|
3821 | super(...arguments);
|
3822 | |
3823 |
|
3824 |
|
3825 | this.routes = {
|
3826 | GET: [],
|
3827 | POST: [],
|
3828 | PUT: [],
|
3829 | PATCH: [],
|
3830 | DELETE: [],
|
3831 | HEAD: [],
|
3832 | OPTIONS: []
|
3833 | };
|
3834 | |
3835 |
|
3836 |
|
3837 |
|
3838 | this.middleware = ware();
|
3839 | }
|
3840 | get config() {
|
3841 | return container_1.lookup('service:config');
|
3842 | }
|
3843 | |
3844 |
|
3845 |
|
3846 |
|
3847 |
|
3848 |
|
3849 | map(fn) {
|
3850 | debug('mapping routes');
|
3851 | fn(this);
|
3852 | }
|
3853 | |
3854 |
|
3855 |
|
3856 |
|
3857 |
|
3858 | async handle(req, res) {
|
3859 | let serverConfig = this.config.get('server');
|
3860 | let request = new request_1.default(req, serverConfig);
|
3861 | try {
|
3862 | debug(`[${request.id}]: ${request.method.toUpperCase()} ${request.path}`);
|
3863 |
|
3864 | await bluebird_1.fromNode((cb) => this.middleware.run(request, res, cb));
|
3865 |
|
3866 | debug(`[${request.id}]: routing request`);
|
3867 | let routes = this.routes[request.method];
|
3868 | if (routes) {
|
3869 |
|
3870 | for (let i = 0; i < routes.length; i += 1) {
|
3871 | request.params = routes[i].match(request.path);
|
3872 | if (request.params) {
|
3873 | request.route = routes[i];
|
3874 | break;
|
3875 | }
|
3876 | }
|
3877 | }
|
3878 |
|
3879 | if (!request.route) {
|
3880 | let availableRoutes = routes && routes.map((r) => r.spec);
|
3881 | debug(`[${request.id}]: ${request.method} ${request.path} did match any route. Available ${request.method} routes:\n${availableRoutes.join(',\n') || 'none'}`);
|
3882 | let error = new errors_1.default.NotFound('Route not recognized');
|
3883 | error.meta = { availableRoutesForMethod: routes || [] };
|
3884 | throw error;
|
3885 | }
|
3886 |
|
3887 | let action = new request.route.action();
|
3888 |
|
3889 | debug(`[${request.id}]: running action`);
|
3890 | await action.run(request, res);
|
3891 | }
|
3892 | catch (error) {
|
3893 | await this.handleError(request, res, error);
|
3894 | }
|
3895 | }
|
3896 | |
3897 |
|
3898 |
|
3899 |
|
3900 | async handleError(request, res, error) {
|
3901 | request.params = request.params || {};
|
3902 | request.params.error = error;
|
3903 | let ErrorAction = container_1.lookup('action:error');
|
3904 | let errorAction = new ErrorAction();
|
3905 | return errorAction.run(request, res);
|
3906 | }
|
3907 | |
3908 |
|
3909 |
|
3910 |
|
3911 |
|
3912 |
|
3913 | use(middleware) {
|
3914 | this.middleware.use(middleware);
|
3915 | }
|
3916 | |
3917 |
|
3918 |
|
3919 |
|
3920 |
|
3921 |
|
3922 |
|
3923 |
|
3924 |
|
3925 |
|
3926 |
|
3927 |
|
3928 | route(method, rawPattern, actionPath, params) {
|
3929 | method = method.toUpperCase();
|
3930 |
|
3931 | let normalizedPattern = rawPattern.replace(/^([^/])/, '/$1');
|
3932 |
|
3933 | normalizedPattern = normalizedPattern.replace(/\/$/, '');
|
3934 |
|
3935 | normalizedPattern = `${normalizedPattern}(/)`;
|
3936 |
|
3937 | let ActionClass = container_1.lookup(`action:${actionPath}`);
|
3938 | let route = new route_1.default(normalizedPattern);
|
3939 | route.actionPath = actionPath;
|
3940 | route.action = ActionClass;
|
3941 | route.additionalParams = params;
|
3942 | if (!route.action) {
|
3943 | throw new Error(`No action found at ${actionPath}`);
|
3944 | }
|
3945 | this.routes[method].push(route);
|
3946 | }
|
3947 | |
3948 |
|
3949 |
|
3950 |
|
3951 |
|
3952 | urlFor(actionPath, data) {
|
3953 | let actionEntry = container_1.lookup(`action:${actionPath}`, { loose: true });
|
3954 | if (actionEntry === false) {
|
3955 | return false;
|
3956 | }
|
3957 | let action = actionEntry;
|
3958 | let route;
|
3959 | lodash_1.forEach(this.routes, (routes) => {
|
3960 | route = lodash_1.find(routes, { action });
|
3961 | return !route;
|
3962 | });
|
3963 | return route && route.reverse(data);
|
3964 | }
|
3965 | |
3966 |
|
3967 |
|
3968 |
|
3969 |
|
3970 | get(rawPattern, actionPath, params) {
|
3971 | this.route('get', rawPattern, actionPath, params);
|
3972 | }
|
3973 | |
3974 |
|
3975 |
|
3976 |
|
3977 |
|
3978 | post(rawPattern, actionPath, params) {
|
3979 | this.route('post', rawPattern, actionPath, params);
|
3980 | }
|
3981 | |
3982 |
|
3983 |
|
3984 |
|
3985 |
|
3986 | put(rawPattern, actionPath, params) {
|
3987 | this.route('put', rawPattern, actionPath, params);
|
3988 | }
|
3989 | |
3990 |
|
3991 |
|
3992 |
|
3993 |
|
3994 | patch(rawPattern, actionPath, params) {
|
3995 | this.route('patch', rawPattern, actionPath, params);
|
3996 | }
|
3997 | |
3998 |
|
3999 |
|
4000 |
|
4001 |
|
4002 | delete(rawPattern, actionPath, params) {
|
4003 | this.route('delete', rawPattern, actionPath, params);
|
4004 | }
|
4005 | |
4006 |
|
4007 |
|
4008 |
|
4009 |
|
4010 | head(rawPattern, actionPath, params) {
|
4011 | this.route('head', rawPattern, actionPath, params);
|
4012 | }
|
4013 | |
4014 |
|
4015 |
|
4016 |
|
4017 |
|
4018 | options(rawPattern, actionPath, params) {
|
4019 | this.route('options', rawPattern, actionPath, params);
|
4020 | }
|
4021 | |
4022 |
|
4023 |
|
4024 |
|
4025 |
|
4026 |
|
4027 |
|
4028 |
|
4029 |
|
4030 |
|
4031 |
|
4032 |
|
4033 |
|
4034 |
|
4035 |
|
4036 |
|
4037 |
|
4038 |
|
4039 |
|
4040 |
|
4041 |
|
4042 |
|
4043 |
|
4044 |
|
4045 |
|
4046 |
|
4047 |
|
4048 |
|
4049 | resource(resourceName, options = {}) {
|
4050 | let plural = inflection_1.pluralize(resourceName);
|
4051 | let collection = `/${plural}`;
|
4052 | let resource = `${collection}/:id`;
|
4053 | let relationship = `${resource}/relationships/:relation`;
|
4054 | let related = `${resource}/:relation`;
|
4055 | if (!options.related) {
|
4056 | options.except = ['related', 'fetch-related', 'replace-related', 'add-related', 'remove-related'].concat(options.except);
|
4057 | }
|
4058 | let hasWhitelist = Boolean(options.only);
|
4059 | options.only = lodash_1.castArray(options.only);
|
4060 | options.except = lodash_1.castArray(options.except);
|
4061 | |
4062 |
|
4063 |
|
4064 |
|
4065 | function include(action) {
|
4066 | let whitelisted = options.only.includes(action);
|
4067 | let blacklisted = options.except.includes(action);
|
4068 | return !blacklisted && ((hasWhitelist && whitelisted) ||
|
4069 | !hasWhitelist);
|
4070 | }
|
4071 | [
|
4072 | ['list', 'get', collection],
|
4073 | ['create', 'post', collection],
|
4074 | ['show', 'get', resource],
|
4075 | ['update', 'patch', resource],
|
4076 | ['destroy', 'delete', resource],
|
4077 | ['related', 'get', related],
|
4078 | ['fetch-related', 'get', relationship],
|
4079 | ['replace-related', 'patch', relationship],
|
4080 | ['add-related', 'post', relationship],
|
4081 | ['remove-related', 'delete', relationship]
|
4082 | ].forEach((routeTemplate) => {
|
4083 | let [action, method, url] = routeTemplate;
|
4084 | if (include(action)) {
|
4085 | let routeMethod = this[method];
|
4086 | routeMethod.call(this, url, `${plural}/${action}`);
|
4087 | }
|
4088 | });
|
4089 | }
|
4090 | |
4091 |
|
4092 |
|
4093 |
|
4094 |
|
4095 |
|
4096 |
|
4097 |
|
4098 |
|
4099 |
|
4100 |
|
4101 |
|
4102 | namespace(namespace, fn) {
|
4103 | let router = this;
|
4104 | if (namespace.endsWith('/')) {
|
4105 | namespace = namespace.slice(0, namespace.length - 1);
|
4106 | }
|
4107 |
|
4108 | let wrapper = {
|
4109 | get(pattern, actionPath, params) {
|
4110 | router.route('get', `${namespace}/${pattern.replace(/^\//, '')}`, actionPath, params);
|
4111 | },
|
4112 | post(pattern, actionPath, params) {
|
4113 | router.route('post', `${namespace}/${pattern.replace(/^\//, '')}`, actionPath, params);
|
4114 | },
|
4115 | put(pattern, actionPath, params) {
|
4116 | router.route('put', `${namespace}/${pattern.replace(/^\//, '')}`, actionPath, params);
|
4117 | },
|
4118 | patch(pattern, actionPath, params) {
|
4119 | router.route('patch', `${namespace}/${pattern.replace(/^\//, '')}`, actionPath, params);
|
4120 | },
|
4121 | delete(pattern, actionPath, params) {
|
4122 | router.route('delete', `${namespace}/${pattern.replace(/^\//, '')}`, actionPath, params);
|
4123 | },
|
4124 | head(pattern, actionPath, params) {
|
4125 | router.route('head', `${namespace}/${pattern.replace(/^\//, '')}`, actionPath, params);
|
4126 | },
|
4127 | options(pattern, actionPath, params) {
|
4128 | router.route('options', `${namespace}/${pattern.replace(/^\//, '')}`, actionPath, params);
|
4129 | },
|
4130 | resource(resourceName, options) {
|
4131 | router.resource.call(this, resourceName, options);
|
4132 | }
|
4133 | };
|
4134 |
|
4135 | if (fn) {
|
4136 | fn(wrapper);
|
4137 | }
|
4138 | }
|
4139 | }
|
4140 | exports.default = Router;
|
4141 |
|
4142 | });
|
4143 |
|
4144 |
|
4145 |
|
4146 |
|
4147 |
|
4148 |
|
4149 | loader.add('/lib/runtime/service.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4150 |
|
4151 | "use strict";
|
4152 | Object.defineProperty(exports, "__esModule", { value: true });
|
4153 | const object_1 = require("../metal/object");
|
4154 |
|
4155 |
|
4156 |
|
4157 |
|
4158 |
|
4159 |
|
4160 |
|
4161 |
|
4162 |
|
4163 |
|
4164 |
|
4165 |
|
4166 | class Service extends object_1.default {
|
4167 | }
|
4168 | exports.default = Service;
|
4169 |
|
4170 | });
|
4171 |
|
4172 |
|
4173 |
|
4174 |
|
4175 |
|
4176 |
|
4177 | loader.add('/lib/test/acceptance-test.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4178 |
|
4179 | "use strict";
|
4180 | Object.defineProperty(exports, "__esModule", { value: true });
|
4181 | const path = require("path");
|
4182 | const glob_1 = require("glob");
|
4183 | const bluebird_1 = require("bluebird");
|
4184 | const lodash_1 = require("lodash");
|
4185 | const mock_request_1 = require("./mock-request");
|
4186 | const mock_response_1 = require("./mock-response");
|
4187 |
|
4188 |
|
4189 |
|
4190 |
|
4191 |
|
4192 |
|
4193 |
|
4194 |
|
4195 |
|
4196 |
|
4197 | class AcceptanceTest {
|
4198 | constructor() {
|
4199 | |
4200 |
|
4201 |
|
4202 |
|
4203 |
|
4204 |
|
4205 | this.headers = {
|
4206 | accept: 'application/json',
|
4207 | 'content-type': 'application/json'
|
4208 | };
|
4209 | |
4210 |
|
4211 |
|
4212 | this._injections = {};
|
4213 | let compiledPath = path.join(process.cwd(), process.env.DENALI_TEST_BUILD_DIR);
|
4214 | let bundleFile = glob_1.sync(path.join(compiledPath, '*.bundle.js'))[0];
|
4215 | let bundle = require(bundleFile);
|
4216 | this.container = bundle();
|
4217 | let Application = this.container.lookup('app:application');
|
4218 | this.application = new Application(this.container.loader, { environment: process.env.NODE_ENV || 'test' });
|
4219 | }
|
4220 | |
4221 |
|
4222 |
|
4223 |
|
4224 |
|
4225 |
|
4226 |
|
4227 |
|
4228 |
|
4229 |
|
4230 | static setupTest() {
|
4231 | let ava = require('ava');
|
4232 | ava.beforeEach(async (t) => {
|
4233 | let acceptanceTest = new AcceptanceTest();
|
4234 | await acceptanceTest.setup(t.context);
|
4235 | });
|
4236 | ava.afterEach.always(async (t) => {
|
4237 | await t.context.app.teardown();
|
4238 | });
|
4239 | return ava;
|
4240 | }
|
4241 | async setup(context) {
|
4242 | context.app = this;
|
4243 | await this.start();
|
4244 | let adapters = this.container.lookupAll('orm-adapter');
|
4245 | let transactionInitializers = [];
|
4246 | lodash_1.forEach(adapters, (Adapter) => {
|
4247 | if (typeof Adapter.startTestTransaction === 'function') {
|
4248 | transactionInitializers.push(Adapter.startTestTransaction());
|
4249 | }
|
4250 | });
|
4251 | await bluebird_1.all(transactionInitializers);
|
4252 | }
|
4253 | async teardown() {
|
4254 | let transactionRollbacks = [];
|
4255 | let adapters = this.container.lookupAll('orm-adapter');
|
4256 | lodash_1.forEach(adapters, (Adapter) => {
|
4257 | if (typeof Adapter.rollbackTestTransaction === 'function') {
|
4258 | transactionRollbacks.push(Adapter.rollbackTestTransaction());
|
4259 | }
|
4260 | });
|
4261 | await bluebird_1.all(transactionRollbacks);
|
4262 | await this.shutdown();
|
4263 | }
|
4264 | |
4265 |
|
4266 |
|
4267 |
|
4268 |
|
4269 |
|
4270 | async start() {
|
4271 | await this.application.runInitializers();
|
4272 | }
|
4273 | |
4274 |
|
4275 |
|
4276 |
|
4277 |
|
4278 | async request(options) {
|
4279 | let body = null;
|
4280 | options.headers = lodash_1.mapKeys(options.headers, (value, key) => key.toLowerCase()) || {};
|
4281 | if (options.body) {
|
4282 | body = typeof options.body === 'string' ? options.body : JSON.stringify(options.body);
|
4283 | options.headers['transfer-encoding'] = 'chunked';
|
4284 | }
|
4285 | let req = new mock_request_1.default({
|
4286 | method: options.method.toUpperCase(),
|
4287 | url: options.url,
|
4288 | headers: lodash_1.assign({}, this.headers, options.headers)
|
4289 | });
|
4290 | return new Promise((resolve, reject) => {
|
4291 | let res = new mock_response_1.default(({ status, body, json }) => {
|
4292 | if (status < 500) {
|
4293 | resolve({ status: res.statusCode, body: json || body });
|
4294 | }
|
4295 | else {
|
4296 | reject({ response: res, status, body, json });
|
4297 | }
|
4298 | });
|
4299 |
|
4300 | this.application.router.handle(req, res);
|
4301 | let SIMULATED_WRITE_DELAY = 10;
|
4302 | setTimeout(() => {
|
4303 | if (body) {
|
4304 | req.write(body);
|
4305 | }
|
4306 | req.end();
|
4307 | }, SIMULATED_WRITE_DELAY);
|
4308 | });
|
4309 | }
|
4310 | |
4311 |
|
4312 |
|
4313 |
|
4314 |
|
4315 | async get(url, options = {}) {
|
4316 | return this.request(Object.assign(options, { url, method: 'GET' }));
|
4317 | }
|
4318 | |
4319 |
|
4320 |
|
4321 |
|
4322 |
|
4323 | async head(url, options = {}) {
|
4324 | return this.request(Object.assign(options, { url, method: 'HEAD' }));
|
4325 | }
|
4326 | |
4327 |
|
4328 |
|
4329 |
|
4330 |
|
4331 | async delete(url, options = {}) {
|
4332 | return this.request(Object.assign(options, { url, method: 'DELETE' }));
|
4333 | }
|
4334 | |
4335 |
|
4336 |
|
4337 |
|
4338 |
|
4339 | async post(url, body, options = {}) {
|
4340 | return this.request(Object.assign(options, { url, body, method: 'POST' }));
|
4341 | }
|
4342 | |
4343 |
|
4344 |
|
4345 |
|
4346 |
|
4347 | async put(url, body, options = {}) {
|
4348 | return this.request(Object.assign(options, { url, body, method: 'PUT' }));
|
4349 | }
|
4350 | |
4351 |
|
4352 |
|
4353 |
|
4354 |
|
4355 | async patch(url, body, options = {}) {
|
4356 | return this.request(Object.assign(options, { url, body, method: 'PATCH' }));
|
4357 | }
|
4358 | |
4359 |
|
4360 |
|
4361 |
|
4362 |
|
4363 | getHeader(name) {
|
4364 | name = name.toLowerCase();
|
4365 | return this.headers[name];
|
4366 | }
|
4367 | |
4368 |
|
4369 |
|
4370 |
|
4371 |
|
4372 | setHeader(name, value) {
|
4373 | this.headers[name.toLowerCase()] = value;
|
4374 | }
|
4375 | |
4376 |
|
4377 |
|
4378 |
|
4379 |
|
4380 | removeHeader(name) {
|
4381 | delete this.headers[name.toLowerCase()];
|
4382 | }
|
4383 | |
4384 |
|
4385 |
|
4386 |
|
4387 |
|
4388 | lookup(name) {
|
4389 | return this.container.lookup(name);
|
4390 | }
|
4391 | |
4392 |
|
4393 |
|
4394 |
|
4395 |
|
4396 |
|
4397 | inject(name, value, options) {
|
4398 | this._injections[name] = this.container.lookup(name);
|
4399 | this.container.register(name, value, options);
|
4400 | this.container.clearCache(name);
|
4401 | }
|
4402 | |
4403 |
|
4404 |
|
4405 |
|
4406 |
|
4407 |
|
4408 | restore(name) {
|
4409 | this.container.register(name, this._injections[name]);
|
4410 | delete this._injections[name];
|
4411 | }
|
4412 | |
4413 |
|
4414 |
|
4415 |
|
4416 |
|
4417 | async shutdown() {
|
4418 | await this.application.shutdown();
|
4419 | }
|
4420 | }
|
4421 | exports.AcceptanceTest = AcceptanceTest;
|
4422 | exports.default = AcceptanceTest.setupTest.bind(AcceptanceTest);
|
4423 |
|
4424 | });
|
4425 |
|
4426 |
|
4427 |
|
4428 |
|
4429 |
|
4430 |
|
4431 | loader.add('/lib/test/mock-request.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4432 |
|
4433 | "use strict";
|
4434 | Object.defineProperty(exports, "__esModule", { value: true });
|
4435 | const stream_1 = require("stream");
|
4436 | const url = require("url");
|
4437 | const net_1 = require("net");
|
4438 | const lodash_1 = require("lodash");
|
4439 |
|
4440 |
|
4441 |
|
4442 |
|
4443 |
|
4444 |
|
4445 |
|
4446 | class MockRequest extends stream_1.PassThrough {
|
4447 | constructor(options = {}) {
|
4448 | super();
|
4449 | this.httpVersion = '1.1';
|
4450 | this.headers = {};
|
4451 | this.method = 'GET';
|
4452 | this.url = '/';
|
4453 | this.trailers = {};
|
4454 | this.readable = true;
|
4455 | this.method = options.method || this.method;
|
4456 | let parsedUrl = url.parse(options.url || this.url);
|
4457 | this.url = parsedUrl.path;
|
4458 | if (options.headers) {
|
4459 | this.headers = lodash_1.mapKeys(options.headers, (value, key) => key.toLowerCase());
|
4460 | }
|
4461 | if (options.trailers) {
|
4462 | this.trailers = lodash_1.mapKeys(options.trailers, (value, key) => key.toLowerCase());
|
4463 | }
|
4464 | this.httpVersion = options.httpVersion || this.httpVersion;
|
4465 | this.connection = new net_1.Socket();
|
4466 | Object.defineProperty(this.connection, 'remoteAddress', {
|
4467 | value: '192.168.1.1'
|
4468 | });
|
4469 | Object.defineProperty(this.connection, 'encrypted', {
|
4470 | get: () => {
|
4471 | return parsedUrl.protocol === 'https:';
|
4472 | }
|
4473 | });
|
4474 | let json = options.json;
|
4475 | if (json) {
|
4476 | options.body = JSON.stringify(options.json);
|
4477 | this.headers['content-type'] = this.headers['content-type'] || 'application/json';
|
4478 | }
|
4479 | let body = options.body;
|
4480 | if (body) {
|
4481 | if (isReadableStream(body)) {
|
4482 | body.pipe(this);
|
4483 | }
|
4484 | else {
|
4485 | if (!this.headers['content-length']) {
|
4486 | this.headers['content-length'] = String(body.length);
|
4487 | }
|
4488 | this.write(body);
|
4489 | this.end();
|
4490 | }
|
4491 | }
|
4492 | }
|
4493 | get httpVersionMajor() {
|
4494 | return Number(this.httpVersion.split('.')[0]);
|
4495 | }
|
4496 | get httpVersionMinor() {
|
4497 | return Number(this.httpVersion.split('.')[1]);
|
4498 | }
|
4499 | get socket() {
|
4500 | return this.connection;
|
4501 | }
|
4502 | get rawHeaders() {
|
4503 | return lodash_1.flatMapDeep(this.headers, (value, name) => {
|
4504 | if (Array.isArray(value)) {
|
4505 | return value.map((v) => [name, v]);
|
4506 | }
|
4507 | return [name, value];
|
4508 | });
|
4509 | }
|
4510 | get rawTrailers() {
|
4511 | return lodash_1.flatten(lodash_1.toPairs(this.trailers));
|
4512 | }
|
4513 | setTimeout(msecs, callback) {
|
4514 | return this;
|
4515 | }
|
4516 | destroy() {
|
4517 |
|
4518 | }
|
4519 | }
|
4520 | exports.default = MockRequest;
|
4521 | function isReadableStream(stream) {
|
4522 | return typeof stream.pipe === 'function';
|
4523 | }
|
4524 |
|
4525 | });
|
4526 |
|
4527 |
|
4528 |
|
4529 |
|
4530 |
|
4531 |
|
4532 | loader.add('/lib/test/mock-response.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4533 |
|
4534 | "use strict";
|
4535 | Object.defineProperty(exports, "__esModule", { value: true });
|
4536 | const stream_1 = require("stream");
|
4537 | const net_1 = require("net");
|
4538 | const http_1 = require("http");
|
4539 |
|
4540 |
|
4541 |
|
4542 |
|
4543 |
|
4544 |
|
4545 |
|
4546 |
|
4547 | class MockResponse extends stream_1.Writable {
|
4548 | constructor(callback) {
|
4549 | super();
|
4550 | this._headers = {};
|
4551 |
|
4552 | this.upgrading = false;
|
4553 | this.chunkedEncoding = false;
|
4554 | this.shouldKeepAlive = false;
|
4555 | this.useChunkedEncodingByDefault = false;
|
4556 | this.sendDate = true;
|
4557 |
|
4558 | this.finished = false;
|
4559 | this.headersSent = false;
|
4560 | this.connection = new net_1.Socket();
|
4561 | this._body = '';
|
4562 | this.on('finish', () => {
|
4563 | try {
|
4564 | this._json = JSON.parse(this._body);
|
4565 | }
|
4566 | catch (e) { }
|
4567 | if (callback) {
|
4568 | callback({ status: this.statusCode, body: this._body, json: this._json });
|
4569 | }
|
4570 | });
|
4571 | }
|
4572 | get statusMessage() {
|
4573 | return this._customStatusMessage || http_1.STATUS_CODES[this.statusCode];
|
4574 | }
|
4575 | write(chunk, encoding, cb) {
|
4576 | if (Buffer.isBuffer(chunk)) {
|
4577 | chunk = chunk.toString();
|
4578 | }
|
4579 | this._body += chunk;
|
4580 | if (cb) {
|
4581 | setImmediate(cb);
|
4582 | }
|
4583 | return true;
|
4584 | }
|
4585 |
|
4586 | _implicitHeader() { }
|
4587 | setHeader(name, value) {
|
4588 | this._headers[name] = value;
|
4589 | }
|
4590 | getHeader(name) {
|
4591 | return this._headers[name];
|
4592 | }
|
4593 | getHeaders() {
|
4594 | return this._headers;
|
4595 | }
|
4596 | getHeaderNames() {
|
4597 | return Object.keys(this._headers);
|
4598 | }
|
4599 | hasHeader(name) {
|
4600 | return Boolean(this._headers[name]);
|
4601 | }
|
4602 | removeHeader(name) {
|
4603 | delete this._headers[name];
|
4604 | }
|
4605 | addTrailers(headers) {
|
4606 | throw new Error('Trailing headers are not supported on requests without chunked encoding, and MockResponse does not support chunked encoding yet.');
|
4607 | }
|
4608 | flushHeaders() { }
|
4609 | writeHead(statusCode, statusMessage, headers) {
|
4610 | this.statusCode = statusCode;
|
4611 | if (typeof statusMessage === 'string') {
|
4612 | this._customStatusMessage = statusMessage;
|
4613 | Object.assign(this._headers, headers);
|
4614 | }
|
4615 | else {
|
4616 | Object.assign(this._headers, statusMessage);
|
4617 | }
|
4618 | }
|
4619 | writeContinue() { }
|
4620 | assignSocket(socket) { }
|
4621 | detachSocket(socket) { }
|
4622 | setTimeout(msecs, callback) {
|
4623 | this.connection.setTimeout(msecs, callback);
|
4624 | return this;
|
4625 | }
|
4626 | }
|
4627 | exports.default = MockResponse;
|
4628 |
|
4629 | });
|
4630 |
|
4631 |
|
4632 |
|
4633 |
|
4634 |
|
4635 |
|
4636 | loader.add('/lib/test/unit-test.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4637 |
|
4638 | "use strict";
|
4639 | Object.defineProperty(exports, "__esModule", { value: true });
|
4640 | const bluebird_1 = require("bluebird");
|
4641 | const lodash_1 = require("lodash");
|
4642 |
|
4643 |
|
4644 |
|
4645 |
|
4646 |
|
4647 |
|
4648 |
|
4649 |
|
4650 | class UnitTest {
|
4651 | constructor(_subject, overrideConfig, options = {}) {
|
4652 | this._subject = _subject;
|
4653 | this.overrideConfig = overrideConfig;
|
4654 | this.originalContainerValues = {};
|
4655 |
|
4656 | this.container = global.unitTestBundleContainer;
|
4657 |
|
4658 | if (typeof _subject === 'string') {
|
4659 | overrideConfig[_subject] = true;
|
4660 | }
|
4661 | this.applyContainerOverrideConfig(overrideConfig, options.clearContainer);
|
4662 | }
|
4663 | |
4664 |
|
4665 |
|
4666 |
|
4667 |
|
4668 |
|
4669 |
|
4670 |
|
4671 |
|
4672 |
|
4673 |
|
4674 |
|
4675 |
|
4676 | static setupTest(subject = () => null, overrides = {}, options = {}) {
|
4677 | let ava = require('ava');
|
4678 | let unitTest = new this(subject, overrides, options);
|
4679 | ava.beforeEach(async (t) => await unitTest.setup(t.context));
|
4680 | ava.afterEach.always(async (t) => await unitTest.teardown());
|
4681 | return ava.serial;
|
4682 | }
|
4683 | async setup(context) {
|
4684 |
|
4685 | lodash_1.forEach(this.startingContainerValues, (value, specifier) => {
|
4686 | this.container.register(specifier, value);
|
4687 | });
|
4688 |
|
4689 | context.unit = this;
|
4690 | context.container = this.container;
|
4691 | context.subject = this.subject.bind(this);
|
4692 | context.inject = this.inject.bind(this);
|
4693 | context.restore = this.restore.bind(this);
|
4694 | context.lookup = this.container.lookup.bind(this.container);
|
4695 |
|
4696 | await this.startTestTransactions();
|
4697 | }
|
4698 | |
4699 |
|
4700 |
|
4701 |
|
4702 |
|
4703 |
|
4704 |
|
4705 | applyContainerOverrideConfig(overrideConfig, clearContainer) {
|
4706 |
|
4707 |
|
4708 | this.startingContainerValues = lodash_1.mapValues(overrideConfig, (config, key) => {
|
4709 | return config === true ? this.container.lookup(key, { raw: true, loose: true }) : config;
|
4710 | });
|
4711 | if (clearContainer !== false) {
|
4712 | this.container.clear();
|
4713 | }
|
4714 | }
|
4715 | |
4716 |
|
4717 |
|
4718 |
|
4719 |
|
4720 |
|
4721 |
|
4722 | subject() {
|
4723 | if (typeof this._subject === 'string') {
|
4724 | return this.container.lookup(this._subject);
|
4725 | }
|
4726 | return this._subject();
|
4727 | }
|
4728 | inject(nameOrInjections, value, options) {
|
4729 | let injections;
|
4730 | if (typeof nameOrInjections === 'string') {
|
4731 | let name = nameOrInjections;
|
4732 | injections = { [name]: { value, options } };
|
4733 | }
|
4734 | else {
|
4735 | injections = lodash_1.mapValues(nameOrInjections, (value) => ({ value }));
|
4736 | }
|
4737 | lodash_1.forEach(injections, ({ value, options }, specifier) => {
|
4738 | this.originalContainerValues[specifier] = this.container.lookup(specifier, { raw: true, loose: true });
|
4739 | this.container.register(specifier, value, options);
|
4740 | this.container.clearCache(specifier);
|
4741 | });
|
4742 | }
|
4743 | |
4744 |
|
4745 |
|
4746 |
|
4747 |
|
4748 |
|
4749 |
|
4750 | restore(...specifiers) {
|
4751 | if (specifiers.length === 0) {
|
4752 | specifiers = Object.keys(this.originalContainerValues);
|
4753 | }
|
4754 | specifiers.forEach((specifier) => {
|
4755 | this.container.clearCache(specifier);
|
4756 | let originalValue = this.originalContainerValues[specifier];
|
4757 | if (originalValue != null) {
|
4758 | this.container.register(specifier, originalValue);
|
4759 | }
|
4760 | delete this.originalContainerValues[specifier];
|
4761 | });
|
4762 | }
|
4763 | |
4764 |
|
4765 |
|
4766 |
|
4767 | async startTestTransactions() {
|
4768 | let adapters = this.container.lookupAll('orm-adapter');
|
4769 | let transactionInitializers = [];
|
4770 | lodash_1.forEach(adapters, (Adapter) => {
|
4771 | if (typeof Adapter.startTestTransaction === 'function') {
|
4772 | transactionInitializers.push(Adapter.startTestTransaction());
|
4773 | }
|
4774 | });
|
4775 | await bluebird_1.all(transactionInitializers);
|
4776 | }
|
4777 | |
4778 |
|
4779 |
|
4780 | async rollbackTestTransactions() {
|
4781 | let transactionRollbacks = [];
|
4782 | let adapters = this.container.lookupAll('orm-adapter');
|
4783 | lodash_1.forEach(adapters, (Adapter) => {
|
4784 | if (typeof Adapter.rollbackTestTransaction === 'function') {
|
4785 | transactionRollbacks.push(Adapter.rollbackTestTransaction());
|
4786 | }
|
4787 | });
|
4788 | await bluebird_1.all(transactionRollbacks);
|
4789 | }
|
4790 | async teardown() {
|
4791 | this.container.clear();
|
4792 | await this.rollbackTestTransactions();
|
4793 | }
|
4794 | }
|
4795 | exports.UnitTest = UnitTest;
|
4796 | exports.default = UnitTest.setupTest.bind(UnitTest);
|
4797 |
|
4798 | });
|
4799 |
|
4800 |
|
4801 |
|
4802 |
|
4803 |
|
4804 |
|
4805 | loader.add('/lib/utils/json-api.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4806 |
|
4807 | "use strict";
|
4808 | Object.defineProperty(exports, "__esModule", { value: true });
|
4809 |
|
4810 | });
|
4811 |
|
4812 |
|
4813 |
|
4814 |
|
4815 |
|
4816 |
|
4817 | loader.add('/lib/utils/result.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4818 |
|
4819 | "use strict";
|
4820 | Object.defineProperty(exports, "__esModule", { value: true });
|
4821 | function result(valueOrFn, ...args) {
|
4822 | if (typeof valueOrFn === 'function') {
|
4823 | return valueOrFn(...args);
|
4824 | }
|
4825 | else {
|
4826 | return valueOrFn;
|
4827 | }
|
4828 | }
|
4829 | exports.default = result;
|
4830 |
|
4831 | });
|
4832 |
|
4833 |
|
4834 |
|
4835 |
|
4836 |
|
4837 |
|
4838 | loader.add('/lib/utils/rewrap.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4839 |
|
4840 | "use strict";
|
4841 | Object.defineProperty(exports, "__esModule", { value: true });
|
4842 | const denali_cli_1 = require("denali-cli");
|
4843 | const wrap = require("wordwrap");
|
4844 |
|
4845 |
|
4846 |
|
4847 |
|
4848 |
|
4849 |
|
4850 |
|
4851 | function rewrap(strings, ...expressions) {
|
4852 | let text = denali_cli_1.unwrap(strings, ...expressions);
|
4853 | text = wrap(text, Math.min(100, process.stdout.columns));
|
4854 | return text;
|
4855 | }
|
4856 | exports.default = rewrap;
|
4857 |
|
4858 | });
|
4859 |
|
4860 |
|
4861 |
|
4862 |
|
4863 |
|
4864 |
|
4865 | loader.add('/lib/utils/set-if-not-empty.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4866 |
|
4867 | "use strict";
|
4868 | Object.defineProperty(exports, "__esModule", { value: true });
|
4869 | const lodash_1 = require("lodash");
|
4870 | function setIfNotEmpty(obj, key, value) {
|
4871 | if (lodash_1.isArray(value) || !lodash_1.isEmpty(value)) {
|
4872 | lodash_1.set(obj, key, value);
|
4873 | }
|
4874 | }
|
4875 | exports.default = setIfNotEmpty;
|
4876 |
|
4877 | });
|
4878 |
|
4879 |
|
4880 |
|
4881 |
|
4882 |
|
4883 |
|
4884 | loader.add('/lib/utils/strings.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4885 |
|
4886 | "use strict";
|
4887 | Object.defineProperty(exports, "__esModule", { value: true });
|
4888 | const dedent = require("dedent-js");
|
4889 | const util_1 = require("util");
|
4890 | exports.default = {
|
4891 |
|
4892 |
|
4893 |
|
4894 | ContainerEntryNotFound(specifier, registryEntries, resolverNames) {
|
4895 | let registrationsOverview;
|
4896 | if (registryEntries.length > 0) {
|
4897 | registrationsOverview = dedent `
|
4898 | Available manual registrations (via container.register(...)):
|
4899 | - ${registryEntries.join('\n - ')}
|
4900 | `;
|
4901 | }
|
4902 | else {
|
4903 | registrationsOverview = dedent `
|
4904 | There were no manually registered entries in the container.
|
4905 | `;
|
4906 | }
|
4907 | let resolversOverview;
|
4908 | if (resolverNames.length > 0) {
|
4909 | resolversOverview = dedent `
|
4910 | Available resolvers:
|
4911 | - ${resolverNames.join('\n - ')}
|
4912 | `;
|
4913 | }
|
4914 | else {
|
4915 | resolversOverview = dedent `
|
4916 | There were no resolvers available in the container.
|
4917 | `;
|
4918 | }
|
4919 | return dedent `
|
4920 | You tried to lookup a container entry under ${specifier}, but the
|
4921 | container has no such entry.
|
4922 |
|
4923 | ${registrationsOverview}
|
4924 |
|
4925 | ${resolversOverview}
|
4926 |
|
4927 | Run with DEBUG=verbose-denali:resolver:<resolver name> to trace a specific
|
4928 | resolver's resolution
|
4929 | `;
|
4930 | },
|
4931 | ContainerEntryNotAConstructor(specifier, value) {
|
4932 | let str = dedent `
|
4933 | You flagged ${specifier} as a singleton, so the container expected to
|
4934 | a constructor function under that entry.
|
4935 | `;
|
4936 | if (value === undefined) {
|
4937 | str += dedent `
|
4938 | Instead it found 'undefined'. Did you forget to add 'export default'
|
4939 | to a file?
|
4940 | `;
|
4941 | }
|
4942 | else {
|
4943 | str += dedent `
|
4944 | Instead it found:
|
4945 |
|
4946 | ${util_1.inspect(value)}
|
4947 | `;
|
4948 | }
|
4949 | return str;
|
4950 | }
|
4951 | };
|
4952 |
|
4953 | });
|
4954 |
|
4955 |
|
4956 |
|
4957 |
|
4958 |
|
4959 |
|
4960 | loader.add('/lib/utils/topsort.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4961 |
|
4962 | "use strict";
|
4963 | Object.defineProperty(exports, "__esModule", { value: true });
|
4964 | const dag_map_1 = require("dag-map");
|
4965 |
|
4966 |
|
4967 |
|
4968 |
|
4969 |
|
4970 |
|
4971 | function topsort(items, options = {}) {
|
4972 | let graph = new dag_map_1.default();
|
4973 | items.forEach((item) => {
|
4974 | let value = options.valueKey ? item[options.valueKey] : item;
|
4975 | graph.add(item.name, value, item.before, item.after);
|
4976 | });
|
4977 | let sorted = [];
|
4978 | graph.topsort((key, value) => {
|
4979 | sorted.push(value);
|
4980 | });
|
4981 | return sorted;
|
4982 | }
|
4983 | exports.default = topsort;
|
4984 |
|
4985 | });
|
4986 |
|
4987 |
|
4988 |
|
4989 |
|
4990 |
|
4991 |
|
4992 | loader.add('/lib/utils/types.js', {"isMain":false}, function(module, exports, require, __dirname, __filename) {
|
4993 |
|
4994 | "use strict";
|
4995 | Object.defineProperty(exports, "__esModule", { value: true });
|
4996 |
|
4997 | });
|
4998 |
|
4999 |
|
5000 |
|
5001 | });
|
5002 | })();
|
5003 |
|
5004 |
|