1 | <img src="https://digitalbazaar.com/wp-content/uploads/BedrockLogo.png">
|
2 |
|
3 | [![Build Status](https://ci.digitalbazaar.com/buildStatus/icon?job=bedrock)](https://ci.digitalbazaar.com/job/bedrock)
|
4 | [![Dependency Status](https://img.shields.io/david/digitalbazaar/bedrock.svg)](https://david-dm.org/digitalbazaar/bedrock)
|
5 |
|
6 | A core foundation for rich Web applications.
|
7 |
|
8 | ## Overview
|
9 |
|
10 | When creating a Web app, you need a foundation on which to build. There are
|
11 | a lot of disparate technologies out there that can be brought together into
|
12 | a cohesive whole to make this happen. The trouble is in finding, vetting,
|
13 | testing, and combining these technologies -- all of which needs to happen
|
14 | before you can begin to make serious progress on your own project.
|
15 |
|
16 | Bedrock helps you launch your ideas faster by bundling all the best-of-breed
|
17 | tooling that's necessary to build a modern, scalable Web app. It creates a
|
18 | solid foundation on which you can build, letting you focus on your
|
19 | project-specific needs.
|
20 |
|
21 | Bedrock uses a modular design to help keep code well-organized and to allow an
|
22 | ecosystem to grow without unnecessary hindrance. Bedrock keeps its core simple:
|
23 | it provides a powerful configuration system, an event-based API, Linked
|
24 | Data-capabilities, and testing infrastructure that makes writing interactive
|
25 | modules easy. Bedrock is an opinionated, but flexible framework; it tells
|
26 | developers that there's one recommended way to accomplish a task, but if need
|
27 | be, a developer can go in another direction. Many of Bedrock's modules attempt
|
28 | to emulate this approach, creating organizing priniciples and clear guidelines
|
29 | for developers to follow that help break down problems and reduce cognitive
|
30 | load.
|
31 |
|
32 | Bedrock uses node.js and runs on Linux, Mac OS X, and Windows. It can run on a
|
33 | low-powered laptop all the way up to an enterprise server.
|
34 |
|
35 | ## Runnable Examples
|
36 |
|
37 | A very basic, runnable "Hello World" bedrock example can be found
|
38 | at [bedrock-hello-world](https://github.com/digitalbazaar/bedrock-hello-world).
|
39 |
|
40 | More complex, runnable examples can be found at [bedrock-examples](https://github.com/digitalbazaar/bedrock-examples).
|
41 |
|
42 | ## Quick Examples
|
43 |
|
44 | ```
|
45 | npm install bedrock
|
46 | ```
|
47 |
|
48 | Create a MEAN stack application:
|
49 |
|
50 | ```js
|
51 | var bedrock = require('bedrock');
|
52 |
|
53 | // modules
|
54 | require('bedrock-express');
|
55 | require('bedrock-docs');
|
56 | require('bedrock-i18n');
|
57 | require('bedrock-mongodb');
|
58 | require('bedrock-protractor');
|
59 | require('bedrock-request-limiter');
|
60 | require('bedrock-requirejs');
|
61 | require('bedrock-server');
|
62 | require('bedrock-session-mongodb');
|
63 | require('bedrock-validation');
|
64 | require('bedrock-views');
|
65 |
|
66 | bedrock.start();
|
67 | ```
|
68 |
|
69 | To include the [AngularJS][]-based frontend, `bower install` these modules:
|
70 |
|
71 | ```
|
72 | bedrock-angular
|
73 | bedrock-angular-alert
|
74 | bedrock-angular-filters
|
75 | bedrock-angular-form
|
76 | bedrock-angular-lazy-compile
|
77 | bedrock-angular-modal
|
78 | bedrock-angular-model
|
79 | bedrock-angular-selector
|
80 | bedrock-angular-ui
|
81 | ```
|
82 |
|
83 | Create a simple express-based bedrock application:
|
84 |
|
85 | ```js
|
86 | var bedrock = require('bedrock');
|
87 |
|
88 | // modules
|
89 | require('bedrock-express');
|
90 |
|
91 | bedrock.events.on('bedrock-express.configure.routes', function(app) {
|
92 | app.get('/', function(req, res) {
|
93 | res.send('Hello World!');
|
94 | });
|
95 | });
|
96 |
|
97 | bedrock.start();
|
98 | ```
|
99 |
|
100 | Create a bedrock REST application with an express server, mongodb database,
|
101 | and mongodb-backed session storage:
|
102 |
|
103 | ```js
|
104 | var bedrock = require('bedrock');
|
105 |
|
106 | // modules
|
107 | require('bedrock-express');
|
108 | require('bedrock-session-mongodb');
|
109 | var database = require('bedrock-mongodb');
|
110 |
|
111 | bedrock.events.on('bedrock-mongodb.ready', function(callback) {
|
112 | database.openCollections(['people'], function(err) {
|
113 | if(err) {
|
114 | return callback(err);
|
115 | }
|
116 | callback();
|
117 | });
|
118 | });
|
119 |
|
120 | bedrock.events.on('bedrock-express.configure.routes', function(app) {
|
121 | app.get('/people', function(req, res, next) {
|
122 | database.collections.people.find({}).toArray(function(err, docs) {
|
123 | if(err) {
|
124 | return next(err);
|
125 | }
|
126 | res.send(docs);
|
127 | });
|
128 | });
|
129 |
|
130 | app.get('/people/:name', function(req, res, next) {
|
131 | database.collections.people.findOne(
|
132 | {name: req.param('name')}, function(err, result) {
|
133 | if(err) {
|
134 | return next(err);
|
135 | }
|
136 | res.send(result);
|
137 | });
|
138 | });
|
139 |
|
140 | app.post('/people/:name', function(req, res){
|
141 | database.collections.people.insert(
|
142 | [{name: req.param('name')}], function(err, result) {
|
143 | if(err) {
|
144 | return next(err);
|
145 | }
|
146 | res.send(result.result);
|
147 | });
|
148 | });
|
149 |
|
150 | app.delete('/people/:name', function(req, res){
|
151 | database.collections.people.remove(
|
152 | {name: req.param('name')}, function(err, result) {
|
153 | if(err) {
|
154 | return next(err);
|
155 | }
|
156 | res.send(result.result);
|
157 | });
|
158 | });
|
159 | });
|
160 |
|
161 | bedrock.start();
|
162 | ```
|
163 |
|
164 | To create a MEAN stack application with identity management and authentication,
|
165 | see the [bedrock-seed][] project.
|
166 |
|
167 | ## Comprehensive Module Example
|
168 |
|
169 | Below is an example that demonstrates Bedrock's event API. It creates a
|
170 | module with an http server that other modules can attach listeners to. It
|
171 | also registers a `debug` subcommand that displays the listeners that attached
|
172 | to the http server. The example also creates a module that attaches a simple
|
173 | "hello world" listener to the http server. The example demonstrates how to use
|
174 | Bedrock's event API to:
|
175 |
|
176 | 1. Register a subcommand and handle it if is detected when the command line
|
177 | is parsed.
|
178 | 2. Create a modular http server, listen to a privileged port (80), and emit a
|
179 | custom event to allow other modules to attach listeners to the server only
|
180 | after process privileges have been dropped.
|
181 | 3. Execute custom behavior (eg: print the server's registered event listeners)
|
182 | after all other modules have started, if a subcommand was detected.
|
183 |
|
184 | ### Module `bedrock-example-server.js`:
|
185 |
|
186 | ```js
|
187 | var bedrock = require('bedrock');
|
188 | var http = require('http');
|
189 |
|
190 | // setup default module config
|
191 | bedrock.config['example-server'] = {port: 80};
|
192 |
|
193 | var server = http.createServer();
|
194 |
|
195 | // emitted prior to command line parsing
|
196 | bedrock.events.on('bedrock-cli.init', function() {
|
197 | // add a new subcommand executed via: node project.js debug
|
198 | var command = bedrock.program
|
199 | .command('debug')
|
200 | .description('display registered http listeners')
|
201 | .option(
|
202 | '--debug-event <event>',
|
203 | 'The event to print listeners for. [request]')
|
204 | .action(function() {
|
205 | // save the parsed command information
|
206 | bedrock.config.cli.command = command;
|
207 | });
|
208 | });
|
209 |
|
210 | // emitted after the command line has been parsed
|
211 | bedrock.events.on('bedrock-cli.ready', function() {
|
212 | var command = bedrock.config.cli.command;
|
213 | if(command.name() !== 'debug') {
|
214 | // `debug` not specified on the command line, return early
|
215 | return;
|
216 | }
|
217 |
|
218 | // emitted after all bedrock.start listeners have run
|
219 | bedrock.events.on('bedrock.ready', function() {
|
220 | // print out all the listeners that registered with the server
|
221 | var event = command.debugEvent || 'request';
|
222 | var listeners = server.listeners(event);
|
223 | console.log('listeners for event: ' + event);
|
224 | listeners.forEach(function(listener, index) {
|
225 | console.log(index, listener.toString());
|
226 | });
|
227 | });
|
228 | });
|
229 |
|
230 | // emitted before initialization, to allow any further configuration
|
231 | bedrock.events.on('bedrock.configure', function() {
|
232 | if(bedrock.config.foo) {
|
233 | bedrock.config.foo.bar = true;
|
234 | }
|
235 | });
|
236 |
|
237 | // emitted for early initialization, prior to dropping process privileges
|
238 | bedrock.events.on('bedrock.admin.init', function(callback) {
|
239 | // listen on port 80
|
240 | server.listen(bedrock.config['example-server'].port, function() {
|
241 | // ready, call callback to allow bedrock to continue processing events
|
242 | callback();
|
243 | });
|
244 | });
|
245 |
|
246 | // emitted for modules to do or schedule any unprivileged work on start up
|
247 | bedrock.events.on('bedrock.start', function(callback) {
|
248 | // emit a custom event giving other modules access to the example server
|
249 | bedrock.events.emit('example.server.ready', server, function() {
|
250 | callback();
|
251 | });
|
252 | });
|
253 |
|
254 | // emitted after all bedrock.ready listeners have run
|
255 | bedrock.events.on('bedrock.started', function() {
|
256 | console.log('everything is running now');
|
257 | });
|
258 | ```
|
259 |
|
260 | ### Module `bedrock-example-listener.js`:
|
261 |
|
262 | ```js
|
263 | var bedrock = require('bedrock');
|
264 |
|
265 | // load bedrock-example-server dependency
|
266 | require('./bedrock-example-server');
|
267 |
|
268 | // emitted to allow listeners to be attached to the example server
|
269 | bedrock.events.on('example.server.ready', function(server) {
|
270 | server.on('request', function(request, response) {
|
271 | response.writeHead(200, {'Content-Type': 'text/plain'});
|
272 | response.end('Hello World\n');
|
273 | });
|
274 | });
|
275 | ```
|
276 |
|
277 | ### Example Main Project `project.js`:
|
278 |
|
279 | ```js
|
280 | var bedrock = require('bedrock');
|
281 |
|
282 | // bedrock modules to load
|
283 | require('./bedrock-example-server');
|
284 | require('./bedrock-example-listener');
|
285 |
|
286 | // change the port to use
|
287 | // bedrock.config['example-server'].port = 8123;
|
288 |
|
289 | bedrock.start();
|
290 | ```
|
291 |
|
292 | Run the main project and display the debug information with:
|
293 |
|
294 | ```
|
295 | node project.js debug --debug-event request
|
296 | ```
|
297 |
|
298 | Example output:
|
299 |
|
300 | ```
|
301 | 2015-03-05T21:59:23.727Z - info: starting bedrock...
|
302 | 2015-03-05T21:59:23.729Z - info: running bedrock master process pid=7705
|
303 | 2015-03-05T21:59:23.904Z - info: running bedrock worker process workerPid=7711
|
304 | 2015-03-05T21:59:23.906Z - info: startup time: 6ms workerPid=7711
|
305 | listeners for event: request
|
306 | 0 'function (request, response) {\n response.writeHead(200, {\'Content-Type\': \'text/plain\'});\n response.end(\'Hello World\\n\');\n }'
|
307 | everything is running now
|
308 | ```
|
309 |
|
310 | ## Configuration
|
311 |
|
312 | For documentation on Bedrock's core configuration, see [config.js](./lib/config.js).
|
313 |
|
314 | ## How It Works
|
315 |
|
316 | Bedrock is a modular system built on node.js. Node.js modules typically
|
317 | communicate with each other using the CommonJS API (eg: `require` and
|
318 | `module.exports`, etc.), and Bedrock modules are no different. However,
|
319 | Bedrock also provides some additional low-level subsystems to help modules
|
320 | coordinate. These include: `bedrock.config`, `bedrock.events`,
|
321 | `bedrock.jsonld`, `bedrock.loggers`, `bedrock.test`, and `bedrock.util`.
|
322 |
|
323 | To create a Bedrock project, all you need to do is create a JavaScript file,
|
324 | for example `project.js`, that requires `bedrock`, any other Bedrock modules
|
325 | you're interested in, and that then calls `bedrock.start()`. To run your
|
326 | project, run:
|
327 |
|
328 | ```
|
329 | node project.js
|
330 | ```
|
331 |
|
332 | If you're developing your project and you have installed all of the development
|
333 | packages for the Bedrock modules you're using, you can also easily test your
|
334 | project and any of the modules it has included by running:
|
335 |
|
336 | ```
|
337 | node project.js test
|
338 | ```
|
339 |
|
340 | This will execute Bedrock's built-in test framework, running all of the tests
|
341 | that each module has written. This approach ensures you're running tests for
|
342 | your entire project and its dependencies.
|
343 |
|
344 | ### bedrock.config
|
345 |
|
346 | Bedrock has a simple, but highly-customizable configuration system. All
|
347 | configuration variables are stored in a shared JavaScript object
|
348 | `bedrock.config`. The object is partitioned into separate configuration objects
|
349 | that are identified by the object's keys. For example Bedrock introduces the
|
350 | `cli`, `core`, `constants`, `jsonld`, and `loggers` object keys. The best
|
351 | practice for modules to claim their own area in the configuration object is to
|
352 | insert their default configuration object using a key that either matches their
|
353 | module name or that matches their module name minus any `bedrock-` prefix. For
|
354 | example, the [bedrock-server][] module's specific configuration object can be
|
355 | found under `bedrock.config.server`. A `mycompany-feature` module would be
|
356 | found under `bedrock.config['mycompany-feature']`. Modules may define whatever
|
357 | configuration variables they want to using whatever format is appropriate for
|
358 | their own use.
|
359 |
|
360 | The `bedrock.util` module has helpers to setup configurations, and in
|
361 | particular, dynamically computed configurations. Computed values can help to
|
362 | simplify dependency issues by allowing values to be computed at runtime from a
|
363 | function or string template. (Note there is a small cost with computed config
|
364 | values which could be important depending on the use case.)
|
365 |
|
366 | `bedrock.util.config.Config` creates a wrapper around a config object and
|
367 | optional options. This wrapper exposes a new, helpful API that is detailed
|
368 | below. A common setup could look like the following.
|
369 |
|
370 | ```js
|
371 | // an empty config object
|
372 | let config = {};
|
373 | // common options
|
374 | let options = {
|
375 | // the config
|
376 | config: config
|
377 | // local vars used during string template evaluation
|
378 | locals: config
|
379 | };
|
380 | // wrap the config
|
381 | let c = new bedrock.util.config.Config(config, options);
|
382 | ```
|
383 |
|
384 | Bedrock provides a shared wrapper around the common `bedrock.config` as
|
385 | `bedrock.util.config.main`.
|
386 |
|
387 | To do simple sets of config data, use the `set()` API.
|
388 |
|
389 | ```js
|
390 | let c = bedrock.util.config.main;
|
391 | // set a config variable with a path
|
392 | // path components are created as needed
|
393 | c.set('server.port', 8443);
|
394 | // config is now {"server": {"port": 8443}}
|
395 | ```
|
396 |
|
397 | Normal code and the config API can be mixed. A useful helper is `setDefault()`.
|
398 | This call lets you simplify ensuring a full object path exists before setting
|
399 | data. Objects in the path are created as needed.
|
400 |
|
401 | ```js
|
402 | let config = bedrock.config;
|
403 | let c = bedrock.util.config.main;
|
404 | // create container object if needed
|
405 | c.setDefault('accounts.admin', {});
|
406 | // the config is just a normal object
|
407 | config.accounts.admin.name = 'Ima Admin';
|
408 | c.set('accounts.admin.id', 1);
|
409 | // the config object is returned from setDefault()
|
410 | let account123 = c.setDefault('accounts.account123', {});
|
411 | account123.id = 123;
|
412 | account123.name = 'Account 123';
|
413 | ```
|
414 |
|
415 | Computed config values using the `setComputed()` API add on a much more
|
416 | powerful feature where values will be calculated at runtime.
|
417 |
|
418 | ```js
|
419 | let config = bedrock.config;
|
420 | // get the Config wrapper for the default bedrock.config
|
421 | let c = bedrock.util.config.main;
|
422 | // set static values
|
423 | c.set('server.port', 8443);
|
424 | c.set('server.domain', 'bedrock.dev');
|
425 | // set a computed value that uses values from the main config
|
426 | c.setComputed('server.host', () => {
|
427 | return config.server.domain + ':' + config.server.port;
|
428 | });
|
429 | console.log(config.server.host); // "bedrock.dev:8443"
|
430 | ```
|
431 |
|
432 | The logic for a computed value can be any normal code. If source config values
|
433 | are updated the computed values will reflect the change.
|
434 |
|
435 | ```js
|
436 | let config = bedrock.config;
|
437 | let c = bedrock.util.config.main;
|
438 | c.set('server.port', 8443);
|
439 | c.set('server.domain', 'bedrock.dev');
|
440 | c.setComputed('server.host', () => {
|
441 | // only add the port if it's not the well known default
|
442 | if(config.server.port !== 443) {
|
443 | return config.server.domain + ':' + config.server.port;
|
444 | }
|
445 | return config.server.domain;
|
446 | });
|
447 | console.log(config.server.host); // "bedrock.dev:8443"
|
448 | c.set('server.port', 443);
|
449 | console.log(config.server.host); // "bedrock.dev"
|
450 | ```
|
451 |
|
452 | `setComputed()` can be verbose. a wrapper can be created using the standard
|
453 | `bind()` functionality. A helper called `computer()` will do this for you.
|
454 | ```js
|
455 | let config = bedrock.config;
|
456 | let cc = bedrock.util.config.main.computer();
|
457 | cc('server.host', () => {
|
458 | // only add the port if it's not the well known default
|
459 | if(config.server.port !== 443) {
|
460 | return config.server.domain + ':' + config.server.port;
|
461 | }
|
462 | return config.server.domain;
|
463 | });
|
464 | ```
|
465 |
|
466 | Computed values can also be created with [lodash-style string
|
467 | templates](https://lodash.com/docs/#template).
|
468 |
|
469 | ```js
|
470 | let config = bedrock.config;
|
471 | let cc = bedrock.util.config.main.computer();
|
472 | cc('server.baseUri', 'https://${server.host}');
|
473 | console.log(config.server.baseUri); // "https://bedrock.dev:8443"
|
474 | // use locals option to simplify templates
|
475 | cc('base.computed', '${base.a}:${base.b}:${base.c}');
|
476 | cc('base.computed', '${a}:${b}:${c}', {locals: config.base});
|
477 | ```
|
478 |
|
479 | Setting or computing multiple values with one call uses an object notation:
|
480 |
|
481 | ```js
|
482 | let c = bedrock.util.config.main;
|
483 | let cc = c.computer();
|
484 | c.set({
|
485 | 'server.port': 8443,
|
486 | 'server.domain': 'bedrock.dev',
|
487 | 'server.name': 'Bedrock Dev',
|
488 | 'users.admin.id': 1
|
489 | });
|
490 | cc({
|
491 | 'server.url': 'https://${server.domain}:${server.port}',
|
492 | 'users.admin.url': '${server.url}/users/${users.admin.id}'
|
493 | });
|
494 | ```
|
495 |
|
496 | Computed values can be added to an array using indexing or the `pushComputed`
|
497 | feature. If indexing is used the array must already exist or the
|
498 | `{parentDefault: []}` option should be used. `pushComputed` will create the
|
499 | parent array if needed.
|
500 |
|
501 | ```js
|
502 | let config = bedrock.config;
|
503 | let c = bedrock.util.config.main;
|
504 | let cc = c.computer();
|
505 | cc('server.baseUri', 'https://${server.host}');
|
506 | c.setDefault('resources', []);
|
507 | cc('resources[0]', '${server.baseUri}/r/0');
|
508 | c.pushComputed('resources', '${server.baseUri}/r/1');
|
509 | ```
|
510 |
|
511 | ### bedrock.events
|
512 |
|
513 | It's sometimes necessary to allow modules to coordinate with each other in
|
514 | an orderly fashion. To achieve this, Bedrock provides an event API. Bedrock's
|
515 | event API is very similar to node's built-in EventEmitter, but it provides a
|
516 | few additional features.
|
517 |
|
518 | In particular, when emitting an event, Bedrock can wait for a listener to run
|
519 | asynchronous code before executing the next listener. This allows each listener
|
520 | to run synchronously or asynchronously, depending on their individual needs,
|
521 | without worrying that the next listener or the next event will be emitted
|
522 | before they have completed what they need to do.
|
523 |
|
524 | Bedrock's event system also provides another feature, which is the ability to
|
525 | cancel events. Event cancelation allows modules to build-in default
|
526 | behavior that can be canceled by other modules. Whenever a synchronous listener
|
527 | returns `false` or an asynchronous listener passes `false` to its callback, the
|
528 | event will not be emitted to the remaining listeners, and, if a callback was
|
529 | given when the event was emitted, it will be given the `false` value allowing
|
530 | the emitter to take a different action.
|
531 |
|
532 | To a emit an event:
|
533 |
|
534 | ```js
|
535 | bedrock.events.emit('example-module.foo', data, function(err, result) {
|
536 | if(err) {
|
537 | console.log('an error occurred in a listener and the event was canceled');
|
538 | return;
|
539 | }
|
540 | if(result === false) {
|
541 | console.log('the event was canceled, but not due to an error');
|
542 | return;
|
543 | }
|
544 | console.log('the event was not canceled');
|
545 | });
|
546 | ```
|
547 |
|
548 | To create a synchronous listener:
|
549 |
|
550 | ```js
|
551 | bedrock.events.on('example-module.foo', function(data) {
|
552 | if(anErrorOccured) {
|
553 | throw new Error('foo');
|
554 | }
|
555 | if(shouldCancel) {
|
556 | return false;
|
557 | }
|
558 | // do something synchronous
|
559 | });
|
560 | ```
|
561 |
|
562 | To create an asynchronous listener:
|
563 |
|
564 | ```js
|
565 | bedrock.events.on('example-module.foo', function(data, callback) {
|
566 | // because an additional parameter was added to the listener function,
|
567 | // it is assumed it should be a function and a callback will be passed
|
568 | // that *must* be called
|
569 | if(anErrorOccurred) {
|
570 | return callback(new Error('foo'));
|
571 | }
|
572 | if(shouldCancel) {
|
573 | return callback(null, false);
|
574 | }
|
575 | // do something asynchronous, other listeners won't execute and event
|
576 | // emission won't continue until you call the callback
|
577 | process.nextTick(function() {
|
578 | callback();
|
579 | });
|
580 | });
|
581 | ```
|
582 |
|
583 | Note that the asynchronous analog for throwing an error is calling the callback
|
584 | with an error as its first parameter and the analog for returning a value
|
585 | (typically only used for event cancelation) is to pass `null` for the first
|
586 | parameter and the return value for the second parameter of the callback. This
|
587 | API matches the "error-first" callback continuation-style that is standard
|
588 | practice in node.
|
589 |
|
590 | Bedrock core emits several events that modules may listen for. These events
|
591 | fall into three possible namespaces: `bedrock-cli`, `bedrock-loggers` and
|
592 | `bedrock`. The `bedrock-cli` events are emitted to allow coordination with
|
593 | Bedrock's command line interface. The `bedrock-loggers.init` event is emitted
|
594 | after the `bedrock-cli.init` event. The `bedrock` events are emitted after
|
595 | all the `bedrock-cli` events, unless a listener cancels the `bedrock-cli.ready`
|
596 | event or causes the application to exit early.
|
597 |
|
598 | - **bedrock-cli.init**
|
599 | - Emitted before command line parsing. Allows registration of new subcommands.
|
600 | - **bedrock-cli.parsed**
|
601 | - Emitted after command line parsing. Allows for configuration of loggers
|
602 | based on command line flags. For instance, a logger may provide for the
|
603 | specification of a `logGroupName` that may be computed at runtime based
|
604 | on some command line flag(s).
|
605 | - **bedrock-loggers.init**
|
606 | - Emitted after command line parsing. Allows registration of new logging
|
607 | transports prior to initialization of the logging subsystem.
|
608 | - **bedrock-cli.ready**
|
609 | - Emitted after command line parsing and logging initialization. Allows
|
610 | execution of subcommands or the prevention of `bedrock` events from being
|
611 | emitted, either by canceling this event or by exiting the application early.
|
612 | - **bedrock-cli.test.configure**
|
613 | - Emitted during `bedrock-cli.init` after `test` subcommand has been
|
614 | registered. Listeners receive the `test` command object. Allows modules
|
615 | that define new test frameworks to add new `test` command line options via
|
616 | the `test` command object.
|
617 | - **bedrock.test.configure**
|
618 | - Emitted during `bedrock-cli.ready`, before `bedrock.configure`. Allows
|
619 | listeners to make configuration changes for running tests. This event
|
620 | is particularly useful for changing configuration values prior to their
|
621 | later use when `bedrock.configure` is emitted. To make late configuration
|
622 | changes on the basis of whether or not tests are going to run, instead
|
623 | add a listener to the `bedrock.configure` event after any other relevant
|
624 | listeners have been added.
|
625 | - **bedrock.configure**
|
626 | - Emitted after `bedrock-cli.ready` and before `bedrock.admin.init`. Allows
|
627 | additional custom configuration before Bedrock initializes but after
|
628 | command line parsing.
|
629 | - **bedrock.admin.init**
|
630 | - Emitted after `bedrock.configure` and before elevated process privileges
|
631 | are dropped. Allows listeners to perform early initialization tasks that
|
632 | require special privileges. Note that, if Bedrock is started with elevated
|
633 | privileges (ie: as root), listeners will execute with those privileges. Any
|
634 | early initialization that needs to execute before `bedrock.start` but does
|
635 | not require elevated privileges should be deferred to `bedrock.init`. Most
|
636 | modules should find binding to `bedrock.init` to be sufficient for any
|
637 | initialization work.
|
638 | - **bedrock.init**
|
639 | - Emitted after `bedrock.admin.init` and just after elevated process
|
640 | privileges are dropped. Allows listeners to perform early initialization
|
641 | tasks that do not require special privileges. This event should be used
|
642 | to ensure, for example, that a module's API has the required supporting
|
643 | data structures in memory prior to another module's use of it. For example,
|
644 | a validation module may need to load validation schemas from files on disk
|
645 | before they can be accessed via its API, but this loading must occur after
|
646 | the configuration events have passed and after special process privileges
|
647 | have been dropped. **As a best practice, modules should not emit custom
|
648 | events during `bedrock.init` because it may cause scenarios where two
|
649 | unrelated modules can't be easily combined.** For example, if a module emits
|
650 | a custom event during `bedrock.init`, then a listener of that event would
|
651 | be unable to use the API of an unrelated module that hasn't been
|
652 | initialized yet. Deferring custom event emitting to `bedrock.start` solves
|
653 | this problem; it ensures all modules have had a chance to complete
|
654 | initialization before attempting to interact with one another through the
|
655 | event system.
|
656 | - **bedrock.start**
|
657 | - Emitted after `bedrock.init`. This is the event modules should use to
|
658 | execute or schedule their main background behavior and to emit any custom
|
659 | events they would like to make available to their dependents.
|
660 | - **bedrock.ready**
|
661 | - Emitted after `bedrock.start`. Allows listeners to execute custom behavior
|
662 | after all modules have handled the `bedrock.start` event. This event is
|
663 | useful for turning on external access to web services or other modular
|
664 | systems that should now be fully ready for use. It can also be used to run
|
665 | analysis on modules that have started, for example, to build live
|
666 | documentation.
|
667 | - **bedrock.started**
|
668 | - Emitted after `bedrock.ready`. External access to web services or other
|
669 | features provided by modules should now be available. Allows custom
|
670 | subcommands or behavior to run after Bedrock has fully started, eg: tests.
|
671 | - **bedrock.tests.run**
|
672 | - Emitted during `bedrock.started`. Once Bedrock has fully started, this
|
673 | event is emitted to inform test frameworks to run their tests. Listeners
|
674 | are passed a test state object with a `pass` property that they can set to
|
675 | `false` to indicate to the test subsystem that at least one test did not
|
676 | pass. Test frameworks may add their own information to the state object
|
677 | using a property matching their framework name.
|
678 |
|
679 | ### bedrock.jsonld
|
680 |
|
681 | Bedrock is intended to provide a foundation for [Linked Data][] applications,
|
682 | and as such, it provides a [JSON-LD][] processor (via [jsonld.js][]) that is
|
683 | integrated with its configuration system. Any [JSON-LD context][] that is
|
684 | inserted into the `bedrock.config.constants.CONTEXTS` object (where keys
|
685 | are the URL for the context and the values are the context itself), will be
|
686 | served from disk instead of retrieved from the Web. This is a useful feature
|
687 | for both developing [Linked Data][] applications and for ensuring contexts
|
688 | are available in offline mode.
|
689 |
|
690 | ### bedrock.loggers
|
691 |
|
692 | Bedrock has a built-in logging subsystem based on [winston][]. Anything you
|
693 | can do with [winston][], you can do with Bedrock. Bedrock provides a set of
|
694 | default loggers that are suitable for most applications. The main application
|
695 | logger can be retrieved via `bedrock.loggers.get('app')`. A call to
|
696 | `bedrock.loggers.addTransport` can be made in event handlers of the
|
697 | `bedrock-loggers.init` event to add new [winston][] transports. Logging
|
698 | categories (such as `app`) and the transports used by them can be configured
|
699 | via `bedrock.config`.
|
700 |
|
701 | Bedrock supports multi-level child loggers with common metadata. These are
|
702 | created with `bedrock.loggers.get('app').child({...})`. Provided metadata will
|
703 | be added to child log output. A special `module` meta name can optionally be
|
704 | used for pretty output. A shortcut for creating named module loggers is
|
705 | `bedrock.loggers.get('app').child('name')`.
|
706 |
|
707 | Module prefix display can be controlled per-category:
|
708 |
|
709 | ```js
|
710 | // get a child logger with custom module name
|
711 | let logger = bedrock.loggers.get('app').child('my-module');
|
712 |
|
713 | // message module prefix controlled with a per-category config value
|
714 | bedrock.config.loggers.app.bedrock.modulePrefix = false;
|
715 | logger.info('an info message');
|
716 | // module displayed as normal meta data:
|
717 | // 2017-06-30T12:34:56.789Z - info: an info message workerPid=1234, module=my-module
|
718 |
|
719 | // with module prefix enabled:
|
720 | bedrock.config.loggers.app.bedrock.modulePrefix = true;
|
721 | logger.info('an info message');
|
722 | // displayed as an nice message prefix:
|
723 | // 2017-06-30T12:34:56.789Z - info: [my-module] an info message workerPid=1234
|
724 | ```
|
725 |
|
726 | ### bedrock.test
|
727 |
|
728 | Bedrock comes with test support built-in. It provides a test framework based
|
729 | on mocha that integrates with `bedrock.config`. To add a mocha test to a
|
730 | Bedrock module, you simply push a directory or a file path onto the
|
731 | `config.mocha.tests` array. Bedrock also makes it easy to add other test
|
732 | frameworks via Bedrock modules. For example, [bedrock-protractor][] integrates
|
733 | the [AngularJS][] [protractor][] test framework with Bedrock. Whenever you
|
734 | run tests against your project, your project and all of its dependencies will
|
735 | be tested, using whatever test frameworks they have registered with. Bedrock
|
736 | also provides command line options to limit the tests that run as desired.
|
737 |
|
738 | ### bedrock.util
|
739 |
|
740 | Bedrock provides a number of helpful general purpose utilities. For example,
|
741 | Bedrock defines a `BedrockError` class that extends the default `Error`
|
742 | class. A `BedrockError` can keep track of a series of "causes" (other errors)
|
743 | that allow developers to better understand why an error occured.
|
744 | `BedrockError`s can also be marked as `public`, which allows modules that
|
745 | may, for example, serve error information over the Web to display more error
|
746 | details. `bedrock.util` also contains tools for formatting dates,
|
747 | extending/merging/cloning objects, and generating UUIDs.
|
748 |
|
749 | ## Recommended Modules
|
750 |
|
751 |
|
752 |
|
753 | [bedrock-server][] provides a core, cluster-based HTTPS server.
|
754 |
|
755 | [bedrock-express][] provides an Express server with reasonable
|
756 | defaults and extra features like the ability to layer static
|
757 | files and directories to support overrides.
|
758 |
|
759 | [bedrock-mongodb][] provides an API for connecting to a MongoDB
|
760 | database and creating and using collections.
|
761 |
|
762 | [bedrock-jobs][] provides a background job scheduler.
|
763 |
|
764 | [bedrock-requirejs][] provides a client-side module loader and
|
765 | autoconfiguration capabilities for bower components.
|
766 |
|
767 | [bedrock-views][] provides server-rendered views with HTML5 + Bootstrap3.
|
768 |
|
769 | [bedrock-angular][] layers on top of [bedrock-views][] to provide
|
770 | client-rendered AngularJS views.
|
771 |
|
772 | [bedrock-idp][] provides user identity and public key management.
|
773 |
|
774 | [bedrock-protractor][] integrates [protractor][] with Bedrock, exposing a
|
775 | powerful end-to-end [AngularJS][] test framework to Bedrock modules.
|
776 |
|
777 | Other Bedrock modules provide REST APIs, user account management, strong
|
778 | cryptography support, DoS protection, digital signatures, Linked Data, and
|
779 | tons of other [FEATURES][]. If you don't need all the fancy features, Bedrock
|
780 | is modular, so you can use only the modules you want.
|
781 |
|
782 | ## Quickstart
|
783 |
|
784 | You can follow the following tutorial to setup and use Bedrock on a Linux or
|
785 | Mac OS X development machine.
|
786 |
|
787 | ## Requirements
|
788 |
|
789 | * Linux, Mac OS X, Windows
|
790 | * node.js >= 0.10.x
|
791 | * npm >= 1.4.x
|
792 |
|
793 | Running Bedrock
|
794 | ---------------
|
795 |
|
796 | Run the following to start up a development server from the source directory:
|
797 |
|
798 | node index.js
|
799 |
|
800 | To add more verbose debugging, use the `--log-level` option:
|
801 |
|
802 | node index.js --log-level debug
|
803 |
|
804 | Running the Tests
|
805 | -----------------
|
806 |
|
807 | Run all tests:
|
808 |
|
809 | npm test
|
810 |
|
811 | Run only the mocha test framework:
|
812 |
|
813 | node index.js test --framework mocha
|
814 |
|
815 | Run a specific mocha test:
|
816 |
|
817 | node index.js test --framework mocha --mocha-test tests/test.js
|
818 |
|
819 | Running the Code Coverage Tool
|
820 | ------------------------------
|
821 |
|
822 | npm run coverage
|
823 |
|
824 | Look at 'coverage.html' using a web browser
|
825 |
|
826 | Features
|
827 | --------
|
828 |
|
829 | For an example list of features provided by Bedrock modules, see the
|
830 | [FEATURES][] file.
|
831 |
|
832 | FAQ
|
833 | ---
|
834 |
|
835 | See the [FAQ][] file for answers to frequently asked questions.
|
836 |
|
837 | Hacking
|
838 | -------
|
839 |
|
840 | See the [CONTRIBUTING][] file for various details for coders about
|
841 | hacking on this project.
|
842 |
|
843 | Authors
|
844 | -------
|
845 |
|
846 | See the [AUTHORS][] file for author contact information.
|
847 |
|
848 | License
|
849 | -------
|
850 |
|
851 | Bedrock and all Bedrock modules are:
|
852 |
|
853 | Copyright (c) 2011-2015 Digital Bazaar, Inc.
|
854 | All Rights Reserved
|
855 |
|
856 | You can use Bedrock for non-commercial purposes such as self-study, research,
|
857 | personal projects, or for evaluation purposes. See the [LICENSE][] file for
|
858 | details about the included non-commercial license information.
|
859 |
|
860 | [AUTHORS]: AUTHORS.md
|
861 | [FEATURES]: FEATURES.md
|
862 | [CONTRIBUTING]: CONTRIBUTING.md
|
863 | [FAQ]: FAQ.md
|
864 | [LICENSE]: LICENSE.md
|
865 | [AngularJS]: https://github.com/angular/angular.js
|
866 | [JSON-LD]: http://json-ld.org
|
867 | [JSON-LD context]: http://www.w3.org/TR/json-ld/#the-context
|
868 | [Linked Data]: http://en.wikipedia.org/wiki/Linked_data
|
869 | [bedrock-angular]: https://github.com/digitalbazaar/bedrock-angular
|
870 | [bedrock-express]: https://github.com/digitalbazaar/bedrock-express
|
871 | [bedrock-idp]: https://github.com/digitalbazaar/bedrock-idp
|
872 | [bedrock-jobs]: https://github.com/digitalbazaar/bedrock-jobs
|
873 | [bedrock-mongodb]: https://github.com/digitalbazaar/bedrock-mongodb
|
874 | [bedrock-protractor]: https://github.com/digitalbazaar/bedrock-protractor
|
875 | [bedrock-requirejs]: https://github.com/digitalbazaar/bedrock-requirejs
|
876 | [bedrock-seed]: https://github.com/digitalbazaar/bedrock-seed
|
877 | [bedrock-server]: https://github.com/digitalbazaar/bedrock-server
|
878 | [bedrock-views]: https://github.com/digitalbazaar/bedrock-views
|
879 | [jsonld.js]: https://github.com/digitalbazaar/jsonld.js
|
880 | [protractor]: https://github.com/angular/protractor
|
881 | [winston]: https://github.com/winstonjs/winston
|